Bug report
Describe the bug
Filtered Postgres Changes subscriptions fail when the filter column is readable by the authenticated role but not by the anon role.
Client.SetAuth(accessToken) is called before the channel is created and subscribed. However, the initial Postgres Changes subscription appears to be validated using the anon role.
This causes Realtime to reject an otherwise valid filter with an error such as:
invalid column for filter tenant_id
The problem occurs when the authenticated role can read the filter column but the anonymous role cannot.
Removing the filter makes the subscription succeed.
To Reproduce
- Create an example table containing a tenant or organization identifier:
create table public.example_table (
id uuid primary key default gen_random_uuid(),
tenant_id uuid not null,
value text
);
-
Enable RLS:
alter table public.example_table enable row level security;
-
Add the table to the Realtime publication:
alter publication supabase_realtime add table public.example_table;
-
Grant the authenticated role SELECT access:
grant select on public.example_table to authenticated;
-
Do not grant the anon role SELECT access to tenant_id.
-
Add an appropriate RLS policy for authenticated users.
-
Create an authenticated Realtime subscription:
client.Realtime.SetAuth(accessToken);
await client.Realtime.ConnectAsync();
var channel = client.Realtime.Channel("filtered-example");
channel.OnPostgresChange(
(_, _) => { },
ListenType.Updates,
new PostgresChangesFilter
{
Schema = "public",
Table = "example_table",
Filter = $"tenant_id=eq.{tenantId}"
});
await channel.Subscribe();
-
Observe an exception similar to:
Supabase.Realtime.Exceptions.RealtimeException:
Unable to subscribe to changes with given parameters.
[event: UPDATE, schema: public, table: example_table,
filters: [{"tenant_id", "eq", "", false}]]
Exception: ERROR P0001 (raise_exception)
invalid column for filter tenant_id
The subscription succeeds when the Filter property is removed.
Expected behavior
The access token configured through Client.SetAuth() should be applied before the server validates the Postgres Changes subscription.
The filter should be validated using the authenticated role from the supplied access token, and the channel should subscribe successfully.
The behavior should not depend on whether the anon role can read the filter column.
Screenshots
Not applicable. The complete exception is included above.
System information
- OS: Windows 11
- Application framework: .NET 10 / WinUI
- Supabase package: 1.6.0
- Supabase.Realtime package: 7.4.0
- Supabase CLI: 2.113.0
- Local Supabase Realtime: 2.68.4
- Browser: Not applicable
- Node.js: Not applicable
Additional context
The example table is included in the supabase_realtime publication, and the filter column is part of the published columns.
The authenticated role has SELECT permission on the filter column. The anon role intentionally does not.
The database function realtime.subscription_check_filters() validates filter columns using the role from the subscription claims. During the initial subscription, that role appears to be anon.
A possible cause is the order in which authentication is applied:
config.postgres_changes is sent with the initial channel join.
- The server validates the Postgres Changes filters during that join.
RealtimeChannel.HandleJoinResponse() appears to send the access-token push only after the Phoenix channel join succeeds.
The authenticated JWT may therefore need to be included in, or applied before, the initial phx_join request.
Bug report
Describe the bug
Filtered Postgres Changes subscriptions fail when the filter column is readable by the
authenticatedrole but not by theanonrole.Client.SetAuth(accessToken)is called before the channel is created and subscribed. However, the initial Postgres Changes subscription appears to be validated using theanonrole.This causes Realtime to reject an otherwise valid filter with an error such as:
invalid column for filter tenant_idThe problem occurs when the authenticated role can read the filter column but the anonymous role cannot.
Removing the filter makes the subscription succeed.
To Reproduce
Enable RLS:
alter table public.example_table enable row level security;
Add the table to the Realtime publication:
alter publication supabase_realtime add table public.example_table;
Grant the
authenticatedrole SELECT access:grant select on public.example_table to authenticated;
Do not grant the
anonrole SELECT access totenant_id.Add an appropriate RLS policy for authenticated users.
Create an authenticated Realtime subscription:
Observe an exception similar to:
Supabase.Realtime.Exceptions.RealtimeException:
Unable to subscribe to changes with given parameters.
[event: UPDATE, schema: public, table: example_table,
filters: [{"tenant_id", "eq", "", false}]]
Exception: ERROR P0001 (raise_exception)
invalid column for filter tenant_id
The subscription succeeds when the
Filterproperty is removed.Expected behavior
The access token configured through
Client.SetAuth()should be applied before the server validates the Postgres Changes subscription.The filter should be validated using the
authenticatedrole from the supplied access token, and the channel should subscribe successfully.The behavior should not depend on whether the
anonrole can read the filter column.Screenshots
Not applicable. The complete exception is included above.
System information
Additional context
The example table is included in the
supabase_realtimepublication, and the filter column is part of the published columns.The
authenticatedrole has SELECT permission on the filter column. Theanonrole intentionally does not.The database function
realtime.subscription_check_filters()validates filter columns using the role from the subscription claims. During the initial subscription, that role appears to beanon.A possible cause is the order in which authentication is applied:
config.postgres_changesis sent with the initial channel join.RealtimeChannel.HandleJoinResponse()appears to send the access-token push only after the Phoenix channel join succeeds.The authenticated JWT may therefore need to be included in, or applied before, the initial
phx_joinrequest.