Is my Supabase key exposed? Anon vs service_role explained
If you built on Supabase, your site almost certainly ships a Supabase key to the browser. That's normal. What matters is which key.
The two kinds of key
- Anon / publishable key (older projects: a JWT whose payload says
"role":"anon"; newer projects: starts withsb_publishable_). Designed to be public. It can only do what your Row Level Security (RLS) policies allow. - Service role / secret key (a JWT with
"role":"service_role", or a key starting withsb_secret_). It bypasses RLS entirely. Anyone who has it can read, change or delete every row in every table.
How to check which one you shipped
- Open your live site, then DevTools → Sources (or Network), and search for
eyJandsb_. - For a JWT, paste the middle section (between the two dots) into any base64 decoder. Look for
"role". - If it says
service_role, or you findsb_secret_, treat it as leaked.
If the service role key leaked
- Rotate it now in the Supabase dashboard under your project's API settings. Removing it from code isn't enough; it's already public.
- Move whatever needed it into a server-side function (a Supabase Edge Function or your own API route).
- Check your tables for data you didn't write.
If it's the anon key, you're not done yet
The anon key is safe only if RLS is on for every table that holds user data. A table with RLS off is readable and writable by anyone with the anon key, which is everyone. In the Supabase dashboard, check that each table shows RLS enabled and has policies that match who should see what.