The Supabase anon key: is it safe to expose?
You found your Supabase anon key sitting in your app's frontend code and now you're worried it's a leak. Good news: this is one of the few keys that's supposed to be there. The bad news: whether that's actually safe depends entirely on one setting. Here's the straight answer.
The short answer
Yes, the anon key is safe to expose — as long as Row Level Security is on. It's public by design: Supabase expects it to ship in your browser code so your app can talk to the database. It is not a secret, and finding it in your frontend is normal, not a breach. What makes it safe (or not) is whether Row Level Security (RLS) is enabled to control what that key can actually read.
What the anon key actually is
The anon (anonymous) key is your project's public API key. It identifies your Supabase project and carries the anon role — a role that is fully subject to your RLS policies. Think of it less like a password and more like your project's public address: knowing it lets someone knock, but your RLS policies decide whether the door opens and what's behind it.
This is a deliberate model. Supabase's security doesn't come from hiding the key (you can't — it has to be in the browser to work); it comes from the policies you write.
With the anon key, security = your RLS policies, not secrecy. The key being visible is fine. The key being able to read data it shouldn't is the problem.
When the anon key IS a problem
The anon key becomes dangerous the moment RLS is off (or a policy is too loose). Without RLS, the anon role can read every row of every table — so anyone can copy your public key from the browser, call the Supabase REST API directly, and pull your whole database. Same public key, completely different outcome, decided entirely by RLS. This is the single most common serious Supabase misconfiguration, and it's especially frequent in apps generated by AI builders, which often create tables without turning RLS on.
The key you must never expose is the service_role key, which bypasses RLS entirely. Both are long eyJ... JWTs and look alike — see the service_role key guide to tell them apart.
How to check your app is actually safe
- Confirm RLS is enabled on every table that holds user or private data, each with explicit policies (Supabase dashboard → Authentication / Table editor).
- Test an unauthenticated read: with only the
anonkey, your database should return nothing it shouldn't. If it returns protected rows, RLS is off or too loose. - Make sure the key in your frontend really is the
anonkey and not theservice_rolekey — decode the JWT and check theroleclaim.
Check whether your anon key is actually safe
Paste your app's URL and our free scan checks from the outside whether your database returns data without a login — the real test of whether your anon key is exposed or protected.
Only scan apps you own or have permission for.What to do
- Leave the anon key where it is — you don't need to hide or rotate it just because it's visible.
- Turn on Row Level Security on every table and write policies for who can read and write each one. This is the actual fix.
- Only worry about rotating if you discover it's really the
service_rolekey, or if you disable/rotate JWT secrets for another reason. - Re-scan to confirm your database no longer returns protected data to the public key.