supabase-js icon indicating copy to clipboard operation
supabase-js copied to clipboard

Realtime RLS API Call not Respecting `private: true` flag

Open kaceycleveland opened this issue 5 months ago • 0 comments

Bug report

  • [X] I confirm this is a bug with Supabase, not with my own application.
  • [X] I confirm I have searched the Docs, GitHub Discussions, and Discord.

Describe the bug

There is more context here in this discord thread: https://discord.com/channels/839993398554656828/1287055628769951754/1287055628769951754

To summarize though, when using supabase-js and following the docs for authorized real time broadcasts, only certain methods respect the { config: { private: true } } flag. More specifically, the REST endpoint for prompting a broadcast as described here does not respect it: https://supabase.com/docs/guides/realtime/broadcast?queryGroups=language&language=js#send-messages-using-rest-calls

A clear and concise description of what the bug is.

To Reproduce

Join a channel as a client with a given RLS policy that only allows for authenticated listeners:

    const channelName = `project_${project.id}`;
    const channel = supabase.channel(channelName, {
      config: { private: true, broadcast: { self: true } },
    });
    
      channel.on("broadcast", { event: "test" }, (payload) =>
      console.log("payload", payload),
    );

    channel.subscribe((status, err) => {
      if (status === "SUBSCRIBED") {
        console.log("Connected!", status);
      } else {
        console.log("realtime error", status);
      }
    });

RLS on realtime.messages:

alter policy "Allow listening for broadcasts for authenticated users only"
on "realtime"."messages"
to authenticated
using (
  (extension = 'broadcast'::text)
);

Trigger a message from a separate machine (in this case, I have a lambda function triggering it using the service key):

      const channelName = `project_${project.data.id}`;
      const channel = supabaseAdmin.channel(channelName, {
        config: { private: true },
      });
      
      channel.send({
      type: 'broadcast',
      event: 'test',
      payload: { message: 'Hi' },
     })

The channel.send function triggers a broadcast on a public channel when I expect it to trigger on a private channel given private: true. This was confirmed to be an issue because the send command has conditional logic based on being connected to the socket. Therefore, the workaround I provided below works because it waits until the subscription is connected first before sending.

Expected behavior

channel.send should send on a private channel instead of a public channel when private: true is set.

Screenshots

If applicable, add screenshots to help explain your problem.

System information

  • OS: Windows WSL
  • Browser (if applies) chrome
  • Version of supabase-js: 2.45.4
  • Version of Node.js: 22.8.0

Additional context

I have a work around that awaits the subscription to the channel before sending.


      const subscribedResult = await new Promise((resolve, reject) => {
        channel.subscribe(async (status, err) => {
          console.log("subscribing...");
          if (status === "SUBSCRIBED") {
            await channel.send({
              type: "broadcast",
              event: "test",
              payload: { message: "Hi" },
            });
            resolve("success");
          } else {
            console.log("realtime error", status);
            reject(err);
          }
        });
      });

kaceycleveland avatar Sep 21 '24 15:09 kaceycleveland