Supabase anon and authenticated grants: the hidden exposure layer
How Supabase anon/authenticated grants interact with RLS, why broad grants create public attack surface, and how to move sensitive access backend-only.
Inside this guide
- RLS policies are not the whole security model; role grants define the first gate.
- Backend-only tables should not grant SELECT/INSERT/UPDATE/DELETE to browser roles.
- Views and functions need the same grant review as tables.
The anon key is public by design
Supabase projects ship a public anon key so browsers can call approved APIs. That is normal. The mistake is treating the key as the control. The actual control is what the anon and authenticated roles are allowed to do.
If those roles have table privileges and a permissive policy, direct API calls can bypass your product screens. Security must hold at the database and API boundary.
Find grants that should not exist
Start with role grants on tables and views. Then review function EXECUTE grants. Public functions can become data access backdoors even when table grants look clean.
select routine_schema, routine_name, grantee, privilege_type
from information_schema.routine_privileges
where grantee in ('PUBLIC', 'anon', 'authenticated')
order by routine_schema, routine_name, grantee;Use revoke-first thinking for sensitive tables
If the browser does not need direct table access, revoke it and move the workflow to a server route. That route can authenticate the user, check tenant membership, apply rate limits, and call Supabase with a server-only key.
This pattern reduces the number of RLS policies you need to maintain. You still keep RLS for defense in depth, but the product path becomes easier to test.
revoke select, insert, update, delete on table public.billing_events from anon, authenticated;
revoke usage on schema private from anon, authenticated;Document intentional public access
Some tables are intentionally public: feature flags, marketing content, or non-sensitive reference data. Keep those exceptions explicit. Name the table, allowed action, policy reason, and verification command.
Unreviewed public grants age badly. They survive product pivots, schema changes, and copied migrations.
FAQ
Can RLS protect a table that grants SELECT to authenticated?
Yes, if policies are correct. But for sensitive backend-only data, removing direct client grants is simpler and safer.
Should anon ever have table access?
Only for deliberately public data. User, billing, admin, and tenant data should not be anon-readable.