Is the Supabase anon key safe to expose?
Practical checklist from ShipSafeStack. Not a penetration test, compliance audit, score, or proof that a project is safe. Informational only — no guarantees. Short answer: Supabase’s docs say the anon key, and the newer
Practical checklist from ShipSafeStack. Not a penetration test, compliance audit, score, or proof that a project is safe. Informational only — no guarantees.
Short answer: Supabase’s docs say the anon key, and the newer publishable key, are meant to be in the browser. They are not a secret. That only holds when row level security is on and the grants are tight. The service_role key and the newer secret key (sb_secret_…) bypass RLS and do not belong in the client.
If RLS is off, or grants are wide open, the anon key is a public handle on a public table. Setup steps: how to set up Supabase RLS for an AI-built app. After policies exist: RLS checklist.
Which key is which
Supabase’s API key docs describe four keys — two for code you ship, two that are elevated:
| Key | Format | What Supabase says |
|---|---|---|
| Publishable key | sb_publishable_… |
Low privilege. OK in a web page or mobile app. Only reaches what RLS allows. |
| Anon key | Long JWT | Legacy publishable key. Same idea: identifies the project; not a secret. |
| Secret key | sb_secret_… |
Elevated. Bypasses RLS. Server / Edge Function / backend you control. |
| Service role key | Long JWT | Legacy secret key. Same bypass. Prefer a secret key where you can. |
A publishable key with no signed-in user acts as the anon Postgres role. With a signed-in user it acts as authenticated. A secret/service_role key bypasses RLS — policies for anon / authenticated do not apply to it.
Creating a publishable or secret key does not revoke the legacy keys until you disable them under Settings → API Keys.
How to tell an anon JWT from a service_role JWT
Both legacy keys are JWTs, so both can start with eyJ. The prefix is not the difference — the payload is.
A JWT is three base64url segments. The middle segment is the payload (encoded, not encrypted). Decode that segment on your own machine and read the role field:
-
roleofanon→ anon key (expected in the client when RLS is correct) -
roleofservice_role→ service role key (never in the client,VITE_/NEXT_PUBLIC_, or a public repo) -
sb_publishable_…→ newer public key;sb_secret_…→ newer secret key
Do not paste live keys into a random website to decode them.
ShipSafeStack’s free passive check reports an anon JWT in public scripts as information; it does not treat that alone as a failure. A service_role JWT in public scripts is a different problem.
When the anon key is the wrong thing to worry about
Worry first about:
- RLS disabled or missing on tables the client can reach
- Policies that only check “signed in” without scoping rows to that user
- Default grants that are wider than your policies
- A service role / secret key that also shipped in the browser, repo, or chat
If the service role key leaked
Treat it as compromised. Remove it from the client first, put a new secret only on the server, rotate at Supabase, and review logs/data. Full steps: Supabase service role key exposed: what to do now.
FAQ (condensed)
- Can the anon key sit in a public GitHub repo? Supabase treats it as non-secret; the risk is still your RLS and grants, plus accidentally committing the service role beside it.
-
Both
eyJkeys shipped? Decode payloads locally; rotate and remove theservice_roleone immediately; keep anon only if RLS is correct. - Does enabling RLS protect tables the service role reads? No — service role bypasses RLS.
-
Lovable / Bolt: public Supabase URL + anon/publishable values often go in client env (
VITE_…); service role belongs in server Secrets / Edge Functions, not in the bundle.
Check a public URL (passive, free): shipsafestack.com/scan — ordinary GETs only; nothing stored; informational only, not an audit.
Original: Is the Supabase anon key safe to expose?
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.