GUIDE · SECURITY

Supabase anon key exposed: is it a problem?

The publishable key (formerly anon) is meant for the browser. The service_role key never is. How to tell them apart.

3 min readLast checked

The difference

Supabase describes the publishable key like this: anyone can read it, and it only reaches what row level security allows. The secret key bypasses row level security and must never leave your own control. Policies do not apply to it because its Postgres role has the BYPASSRLS attribute.

Older projects call the keys anon key and service_role key. They are long tokens that start with eyJ. Supabase points out that a long key starting with eyJ belongs to these older keys.

What follows

Turn on row level security (RLS) for every table before you publish. Without RLS, the public key can do more than you think.

How to tell which key is in your bundle

Open the source of the published page and search for supabase.co and for the keys: sb_publishable_, sb_secret_ and, for older projects, a long eyJ… token. An eyJ… token with the role service_role is the emergency. The check detects such a service_role token in the older format automatically. It does not currently search for sb_secret_, so check that one yourself.

If a secret key was public

Fix the cause first: move everything that needs the secret key to the backend. Supabase advises not to rush and to remove the cause before rotating. Then create a new secret key and replace the old one everywhere. Check that every place uses the new key, and only then delete the old one. Deleting cannot be undone. This is the order described in the Supabase docs.

Common mistakes

The Supabase docs warn against these mistakes when handling keys:

  • Using the secret key in the browser. The docs say it belongs only in backend components such as servers, APIs with their own authorization checks, Edge Functions and microservices. In a browser, Supabase rejects it with HTTP 401.
  • Putting the secret key in source control, CI scripts, chat, e-mail or SMS, or in a URL. The docs advise keeping keys in the secrets storage of the tool you use. It does not belong in full in logs either: at most 6 characters after the prefix.
  • Sending the key in the Authorization: Bearer header. Publishable and secret keys are not JWTs and belong in the apikey header.
  • Forgetting, when moving to the new keys, that Supabase is deprecating the old ones (anon and service_role) by the end of 2026. Turning off the old keys is a separate step.

Example: which key where

The mapping according to the Supabase docs:

  • Browser and shipped apps: publishable key (sb_publishable_…). It may be public because it only reaches what row level security allows.
  • Servers, Edge Functions and other backend components: secret key (sb_secret_…), from a secrets storage, never from the code.
  • Local development: supabase start prints a publishable key and a secret key for the local project. They are unrelated to the hosted project.

Frequently asked questions

Is a public publishable key a problem?

No. Anyone can read it, and it only reaches what row level security allows. That assumes RLS is active on every table.

How do I recognise a secret key?

It starts with sb_secret_. On older projects it is the long service_role key, which starts with eyJ.

What if a secret key was public?

Remove the cause first, then create a new secret key and replace the old one everywhere, confirm, and only then delete the old one. Deleting cannot be undone. For an older key (anon or service_role) you deactivate it instead, in the same Dashboard section; that is reversible in case you missed a client.

Does the secret key always bypass RLS?

No. According to the docs, it bypasses RLS only when the request carries no user access token. If it carries one, the policies of the signed-in user apply, even when the client was initialised with a secret key.

Sources

CHECK YOUR APP

Check your app

The free check loads your app like a visitor and shows what is visible from the outside. You confirm beforehand that you are responsible for the app or authorised to test it.

More guides

All guides →