glossary
Client Role Grants (anon/authenticated)
Client role grants (anon/authenticated) create an API surface, and misusing them exposes data to any client. This page explains it in plain English, then goes deeper into how it works in Supabase/Postgres, what commonly goes wrong, and how to fix it without relying on fragile client-side rules.
What “Client Role Grants (anon/authenticated)” means (plain English)
Giving SELECT/INSERT/UPDATE to client roles means anyone with those credentials can call the table or view.
How Client Role Grants (anon/authenticated) works in Supabase/Postgres (technical)
When tables or views retain grants to PUBLIC/anon/authenticated without matching RLS, the database treats them as publicly accessible endpoints.
Attack paths & failure modes for Client Role Grants (anon/authenticated)
- Authenticated SELECT on a sensitive table: A dashboard widget needed recent activity, so the team granted SELECT to authenticated and queried the table directly.
- View grant exposes sensitive columns: The frontend called a view that joined profiles, billing status, and flags, so the team granted SELECT to authenticated for speed.
- Authenticated SELECT on a sensitive table: The grant made the table readable by every logged-in user, allowing enumeration when the policy was missing or permissive.
- View grant exposes sensitive columns: The view began returning billing data and emails; attackers queried it directly and retrieved columns that were never meant for the browser.
- SELECT/INSERT/UPDATE/DELETE is granted to anon/authenticated, making tables directly reachable from the browser.
- EXECUTE remains granted on functions even after table hardening, exposing privileged operations via RPC.
- Views are granted to client roles and accidentally include sensitive columns or broaden access.
- Permissions drift: a quick dev grant quietly becomes a permanent production exposure.
Why Client Role Grants (anon/authenticated) matters for Supabase security
You lose control over who sees or changes data, which is the root cause of many Supabase leaks. If Client Role Grants (anon/authenticated) remains unresolved, attackers can automate enumeration and unauthorized writes at API speed. Treat it as a production reliability risk as well as a data security risk, because incidents spread quickly once clients discover weak access boundaries.
Common Client Role Grants (anon/authenticated) mistakes that lead to leaks
- Granting SELECT to client roles for convenience.
- Forgetting to revoke INSERT/UPDATE after policies land.
- Trusting UI gating instead of database restrictions.
- Authenticated SELECT on a sensitive table: The grant made the table readable by every logged-in user, allowing enumeration when the policy was missing or permissive.
- View grant exposes sensitive columns: The view began returning billing data and emails; attackers queried it directly and retrieved columns that were never meant for the browser.
Where to look for Client Role Grants (anon/authenticated) in Supabase
- Table/view grants for anon/authenticated (and PUBLIC) on sensitive schemas.
- Function EXECUTE privileges for any RPC that returns data or mutates state.
- Any frontend code that queries REST/RPC directly instead of calling your backend.
How to detect Client Role Grants (anon/authenticated) issues (signals + checks)
Use this as a quick checklist to validate your current state:
- Try the same queries your frontend can run (anon/authenticated). If sensitive rows come back, you have exposure.
- Verify RLS is enabled and (for sensitive tables) forced.
- List policies and look for conditions that don’t bind rows to a user or tenant.
- Audit grants to
anon/authenticatedon sensitive tables and functions. - Authenticated SELECT on a sensitive table: Authenticated is not a permission level.
- Authenticated SELECT on a sensitive table: Grants create an API surface even without UI links.
- Authenticated SELECT on a sensitive table: Backend feeds can redact and scope safely.
- Re-test after every migration that touches security-critical tables or functions.
How to fix Client Role Grants (anon/authenticated) (backend-only + zero-policy posture)
Mockly’s safest default is backend-only access: the browser should not query tables, call RPC, or access Storage directly.
- Decide which operations must remain client-side (often: none for sensitive resources).
- Create server endpoints (API routes or server actions) for required reads/writes.
- Apply hardening SQL: enable+force RLS where relevant, remove broad policies, and revoke grants from client roles.
- Generate signed URLs for private Storage downloads on the server only.
- Re-run a scan and confirm the issue disappears.
- Add a regression check to your release process so drift doesn’t reintroduce exposure. Fixes that worked in linked incidents:
- Authenticated SELECT on a sensitive table: Revoke SELECT from client roles, expose the feed through a backend endpoint, and verify direct REST calls fail.
- View grant exposes sensitive columns: Revoke client access, replace it with a backend endpoint that returns a minimal, documented shape, and treat views/functions as API surfaces in your audits.
Verification checklist for Client Role Grants (anon/authenticated)
- List grants for anon/authenticated and confirm sensitive tables are not directly accessible.
- Attempt a direct REST query from the browser context and confirm it fails for sensitive resources.
- Enumerate functions and confirm sensitive RPCs are not executable by client roles.
- Re-test after every migration or permission change.
- Authenticated SELECT on a sensitive table: Authenticated is not a permission level.
- Authenticated SELECT on a sensitive table: Grants create an API surface even without UI links.
- Authenticated SELECT on a sensitive table: Backend feeds can redact and scope safely.
- Authenticated SELECT on a sensitive table: Verify exposure with direct REST calls.
SQL sanity checks for Client Role Grants (anon/authenticated) (optional, but high signal)
If you prefer evidence over intuition, run a small set of SQL checks after each fix.
The goal is not to memorize catalog tables — it’s to make sure the access boundary you intended is the one Postgres actually enforces:
- Confirm RLS is enabled (and forced where appropriate) for tables tied to this term.
- List policies and read them as plain language: who can do what, under what condition?
- Audit grants for anon/authenticated and PUBLIC on the tables, views, and functions involved.
- If Storage is involved: review bucket privacy and policies for listing/reads.
- If RPC is involved: review EXECUTE grants for functions and whether privileged functions are server-only.
Pair these checks with a direct API access test using client credentials. When both agree, you can ship the fix with confidence.
Over time, keep a small “query pack” for the checks you trust and run it after every migration. That’s how you prevent quiet regressions.
Prevent Client Role Grants (anon/authenticated) drift (so it doesn’t come back)
- Adopt a default: client roles have minimal privileges; backend handles sensitive access.
- Maintain a small allowlist for intentional client-readable resources (ideally none for sensitive data).
- Add repeatable audits for grants and EXECUTE privileges.
- Keep one reusable verification test for “Authenticated SELECT on a sensitive table” and rerun it after every migration that touches this surface.
- Keep one reusable verification test for “View grant exposes sensitive columns” and rerun it after every migration that touches this surface.
Rollout plan for Client Role Grants (anon/authenticated) fixes (without breaking production)
Many hardening changes fail because teams revoke direct access first and only later discover missing backend paths.
Use this sequence to reduce both risk and outage pressure:
- Implement and verify the backend endpoint or server action before permission changes.
- Switch clients to that backend path behind a feature flag when possible.
- Then revoke direct client access (broad grants, permissive policies, public bucket reads, or broad EXECUTE).
- Run direct-access denial tests and confirm authorized backend flows still succeed.
- Re-scan after deployment and again after the next migration.
This turns security fixes into repeatable rollout mechanics instead of one-off emergency changes.
Incident breakdowns for Client Role Grants (anon/authenticated) (real scenarios)
Authenticated SELECT on a sensitive table
Scenario: A dashboard widget needed recent activity, so the team granted SELECT to authenticated and queried the table directly.
What failed: The grant made the table readable by every logged-in user, allowing enumeration when the policy was missing or permissive.
What fixed it: Revoke SELECT from client roles, expose the feed through a backend endpoint, and verify direct REST calls fail.
Why the fix worked: The backend endpoint scopes results per user, logs requests, and rejects unauthorized access, unlike the previous broad grant.
Key takeaways:
- Authenticated is not a permission level.
- Grants create an API surface even without UI links.
- Backend feeds can redact and scope safely.
- Verify exposure with direct REST calls.
Read full example: Authenticated SELECT on a sensitive table
View grant exposes sensitive columns
Scenario: The frontend called a view that joined profiles, billing status, and flags, so the team granted SELECT to authenticated for speed.
What failed: The view began returning billing data and emails; attackers queried it directly and retrieved columns that were never meant for the browser.
What fixed it: Revoke client access, replace it with a backend endpoint that returns a minimal, documented shape, and treat views/functions as API surfaces in your audits.
Why the fix worked: Backend responses are explicit and reviewable, so you stop shipping whatever the view returns to clients.
Key takeaways:
- Views become API surfaces when granted to clients.
- Column leaks happen quickly during schema changes.
- Backend endpoints enforce a stable response contract.
- Audit grants for views and functions as well as tables.
Read full example: View grant exposes sensitive columns
Real-world examples of Client Role Grants (anon/authenticated) (and why they work)
- Authenticated SELECT on a sensitive table — Authenticated SELECT turned a sensitive table into an open endpoint.
- View grant exposes sensitive columns — Granting a convenience view to client roles exposed sensitive columns.
Related terms
- Public Table Exposure →
/glossary/public-table-exposure - RPC EXECUTE Grants →
/glossary/rpc-execute-grants
FAQ
Is Client Role Grants (anon/authenticated) enough to secure my Supabase app?
It’s necessary, but not sufficient. You also need correct grants, secure Storage/RPC settings, and a backend-only access model for sensitive operations.
What’s the quickest way to reduce risk with Client Role Grants (anon/authenticated)?
Remove direct client access to sensitive resources, enable/force RLS where appropriate, and verify via a repeatable checklist that anon/authenticated cannot query what they shouldn’t.
How do I verify the fix is real (not just a UI change)?
Attempt direct API queries using the same client credentials your app ships. If the database denies access (401/403) and your backend endpoints still work, your fix is effective.
Next step
Want a quick exposure report for your own project? Run a scan in Mockly to find public tables, storage buckets, and RPC functions — then apply fixes with verification steps.