next.jssupabasesupabase-databasesupabase-jssupabase-realtime

Supabase Realtime subscription not working with custom JWT and RLS in Next.js + NextAuth setup


I'm building a website using Next.js, NextAuth, and Supabase. I'm not using Supabase's built-in auth — instead, I manage a custom users table and generate custom JWTs using NextAuth during sign-in.

In the JWT, I set the sub claim to the user's UUID from my own users table, and use this to authenticate against Supabase's RLS. Here's a simplified version of the policy I'm using:

CREATE POLICY "Allow users to select their own messages"
ON messages FOR SELECT
USING (auth.uid()::text = user_id::text);

Direct select queries using the authenticated Supabase client work as expected and return only the current user's messages.

Realtime subscriptions (.channel().on('postgres_changes')) connect successfully but do not receive any data after new messages are inserted.

Additional context:

Question:

Why is Supabase Realtime not enforcing RLS correctly with a custom JWT, even though direct queries work?
How can I make Realtime subscriptions respect RLS policies using auth.uid() when using a custom users table and manually generated JWT? Or is it other problem causing the issue?

To test whether this is an RLS issue, I temporarily added a policy that allows all users to select any rows:

CREATE POLICY "temp_test_realtime"
ON messages FOR SELECT
USING (true);

After enabling this, Realtime subscriptions started receiving data correctly for new inserts.

So it seems the issue is related to how Supabase Realtime interacts with RLS when using a custom JWT (not Supabase Auth).


Solution

  • In order to use custom JWT validation in RLS with realtime, you need to manually set the refreshed JWT token in Supabase realtime client too :

    client.realtime.setAuth({your refreshed token})
    

    doc : https://supabase.com/docs/guides/realtime/postgres-changes?queryGroups=database-method&database-method=sql&queryGroups=language&language=dart#refreshed-tokens