Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting CHANNEL_ERROR when trying to connect to private broadcast channel with a simple RLS policy #1111

Open
2 tasks done
teddyhartanto opened this issue Aug 2, 2024 · 10 comments
Labels
bug Something isn't working

Comments

@teddyhartanto
Copy link

teddyhartanto commented Aug 2, 2024

Bug report

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

Describe the bug

I'm building an in-app chat for my application. Chat works fine when the channel is public. But, I can't seem to get it working when I tried making the channels private.
Here's my frontend code:

// utils/supabase/client.ts
import { createBrowserClient } from "@supabase/ssr";

export const createClient = () =>
  createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
  );
// chat.tsx
"use client";

import { createClient } from "@/utils/supabase/client";
// truncated

export default function Chat(/* truncated */) {
  // truncated
  const supabase = createClient();
  React.useEffect(() => {
    supabase.auth.getSession().then((resp) => {
      supabase.realtime.setAuth(resp?.data?.session?.access_token || null);
      const ws = supabase.channel(chatRoomUuid, { config: { private: true } });
      ws.on("broadcast", { event: "message" }, ({ event, type, payload }) => {
        if (payload.userId !== user.id) {
          setMessages((messages) => [...messages, payload as Message]);
        }
      }).subscribe((state, err) => console.log("Sub ", state, err));
      return () => {
        ws.unsubscribe().then((resp) => console.log("Unsub ", resp));
      };
    });
  }, []);
  // truncated

I got the following log in the console:

Sub  CHANNEL_ERROR Error: "You do not have permissions to read from this Topic"
    at Object.eval [as callback] (RealtimeChannel.js:168:47)
<truncated>

My RLS:
image

As you can see, it's a simple RLS. Even then, I'm getting a CHANNEL_ERROR. The connection would succeed if I remove FROM chat_room_members in the RLS policy. For some unknown reason, querying from any table in the policy fails the connection. What's happening?

I combed over docs, github discussions, github issues, and now Discord and I couldn't find anything. Am I missing something obvious here?

Expected behavior

SUBSCRIBED instead of CHANNEL_ERROR

System information

  • OS: Ubuntu 22.04
  • Browser: Chrome
  • Version of supabase/ssr: 0.4.0
  • Version of realtime-js: 2.10.2
@teddyhartanto teddyhartanto added the bug Something isn't working label Aug 2, 2024
@filipecabaco
Copy link
Contributor

do you have other policies on chat_room_members table?

@teddyhartanto
Copy link
Author

teddyhartanto commented Aug 2, 2024

Nope and RLS not enabled at all:
image

I don't use RLS & Data API in my project (public schema)

Should I have enabled RLS and set a policy there too for Realtime Authz to work? I can try that.

@teddyhartanto
Copy link
Author

teddyhartanto commented Aug 2, 2024

(I deleted the previous comment because I tested wrongly and so the result I reported was wrong. Below is the real report)

Okay I tried it out.
image

I set the RLS real simple: allow all authenticated users to view chat_room_members
image

I'm still getting the same CHANNEL_ERROR

@teddyhartanto teddyhartanto reopened this Aug 2, 2024
@filipecabaco
Copy link
Contributor

just for a sanity check, what happens if you have true on the realtime.messages table?

@teddyhartanto
Copy link
Author

teddyhartanto commented Aug 2, 2024

i would get SUBSCRIBED instead of CHANNEL_ERROR if the RLS for realtime.messages is simply set to true.

I've tested from true -> EXIST (SELECT 1) -> (EXISTS ( SELECT 1 FROM chat_room_members)). It is the last one where the channel subscription gives me CHANNEL_ERROR state with an error Error: "You do not have permissions to read from this Topic". Therefore, it seems to be related to the FROM <table> clause

@filipecabaco
Copy link
Contributor

interesting, can you try to do that query in supabase studio impersonating one of your users to see the output of the select?

@w3b6x9
Copy link
Member

w3b6x9 commented Aug 2, 2024

I've tested from true -> EXIST (SELECT 1) -> (EXISTS ( SELECT 1 FROM chat_room_members))

@teddyhartanto i was worried it might be an issue with the access token but if the first two are working then it's correct.

can you try the last one again but fully qualify the table name?

(EXISTS ( SELECT 1 FROM public.chat_room_members))

@teddyhartanto
Copy link
Author

teddyhartanto commented Aug 3, 2024

@w3b6x9 yeah i think it's not the access token. I monitored the WS payloads and I could see that the authenticated JWT token is passed correctly instead of an anon token on phx_join. I also tried logging out and in again.

I have also tried using the fully qualified table name, but it doesn't seem to matter. On save, Supabase Realtime would truncate the table name from public.chat_room_members -> chat_room_members. Furthermore, if the table name is wrong, Supabase Realtime would error on save.

Eg:

  (EXISTS ( SELECT 1 FROM non_existent))

image

@teddyhartanto
Copy link
Author

teddyhartanto commented Aug 3, 2024

@filipecabaco

When RLS Policy is (EXISTS ( SELECT 1 FROM chat_room_members))

image

{"ref":"1","event":"phx_reply","payload":{"status":"error","response":{"reason":"You do not have permissions to read from this Topic"}},"topic":"realtime:19a51893-6168-4b2d-91a6-47b0db323f64"}	

When RLS Policy is (EXISTS ( SELECT 1))

Works fine. Seems like I can listen to the channel.
image

Side note

I doubt it's related, but, there is a warning for postgres_changes in the studio (see screenshot). I inspected the WS payload and saw this in the payload config for phx_join:

postgres_changes: [{event: "*", schema: "public", table: "*"}]

Whereas in my app, the config is just

postgres_changes: []

@filipecabaco
Copy link
Contributor

In Studio you can disable features by going to Filter messages and disabling postgres_changes

Regarding the policies, could you open a ticket in our support system? that will make it easier for me to understand what could be happening

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants