Supabase keys: anon, service_role, publishable, secret
Which Supabase keys can be public: anon and publishable keys vs service_role and secret keys. Where to find each one, and what to do if one leaks.
Aug 2, 2026 · 6 min read · Updated Oct 16, 2026
Field Notes from Thunkle, a studio that takes AI-built apps from prototype to secure, production-ready software.
A Supabase key in your frontend is not automatically a leaked secret. Publishable and legacy anon keys are intended for public clients. Secret and legacy service-role keys are privileged credentials and must stay in trusted server environments.
The important question is what a request can do with that key and the caller's identity. A public key does not make private records safe; effective database permissions, row-level security, storage policies and backend authorization do that work.
If you need those rules checked against your app's actual roles and workflows, our paid Supabase security audit combines developer review with scoped tests. A key search is useful evidence, not a complete security verdict.
Publishable keys: designed for the browser
Keys beginning with sb_publishable_ identify the application or project making a request. They are not a substitute for a user's login token. Public requests and authenticated requests may have different access because the user's identity changes which database rules apply.
It is normal to find a publishable key in a browser bundle. Review what anonymous and authenticated users can actually access before calling it a finding. Conversely, an app can expose private data even when every key is in the intended place.
Secret keys: trusted servers only
Keys beginning with sb_secret_ provide elevated project access. Keep them in trusted server environments, protect the systems that can read them and never serialize them into a page, client component or API response.
If a secret key has shipped to visitors, removing it from source is not enough. Replace affected callers, revoke the exposed credential promptly and investigate what it could access. Check old deployments, generated files and logs as part of the agreed response. Coordinate containment with the system owner, accounting for service disruption.
Legacy anon and service_role keys
The older API keys are JWT-shaped credentials tied to the project's legacy JWT secret. The anon key is intended for public clients; the service_role key is privileged and must not be public.
Do not infer which keys an app uses from its creation date. Inspect the deployed configuration and callers. Supabase recommends moving to publishable and secret keys, which can be managed independently. Follow its current API-key migration guide.
Correction to the earlier version of this article: legacy credentials are not an exposure you must simply live with. The documented replacement path includes updating callers and deactivating the legacy keys. API-key migration and changing the keys used to sign user JWTs are related operational topics, but they are not the same operation.
Where to find each key
Open your project in the Supabase dashboard and go to Project Settings, then API Keys. Newer projects show a publishable key beginning sb_publishable_ and secret keys beginning sb_secret_. Older projects may also show the legacy anon and service_role JWTs.
Copy only the public key (publishable or anon) into the browser-side environment variable your framework expects. Never put a secret or service_role key in a variable with a client prefix such as NEXT_PUBLIC_, VITE_ or REACT_APP_: those prefixes put the value into the JavaScript bundle every visitor downloads.
Quick answers
Someone found my anon key. Am I compromised? Not because the key is visible; it is meant to be. Whether you are exposed depends on your row-level security and grants. If a table has no working policy, the public key can reach it, and the fix is the policy, not hiding the key.
What replaced the anon key? Publishable keys beginning sb_publishable_. They do the same low-privilege browser job and still rely on row-level security to limit access.
What is the difference between the anon key and the service_role key? The anon key is public and subject to row-level security. The service_role key bypasses row-level security entirely and must stay on trusted servers. Shipping it to a browser hands every visitor unrestricted database access.
Can I rotate a legacy service_role key? Not on its own. Migrate to publishable and secret keys, move every caller to the replacements, then deactivate the legacy keys. New sb_secret_ keys can be replaced individually.
How do I know if my service_role key leaked? Search the deployed client bundle, client-side environment variables, repository history and public logs. If it appears in anything sent to a browser, treat it as exposed even without evidence that someone used it.
Review permissions, not just key names
Review which schemas, tables, functions, views and storage objects are exposed, which roles have grants, and which policies apply to each operation. A policy allowing all rows can be intentional for a public catalogue and wrong for private documents.
Views and privileged database functions also need review: their execution context and the executing role's privileges affect whether row policies protect the underlying data. Merely seeing an RLS badge is not enough. Neither is assuming every view bypasses every policy.
Use authorized test accounts and synthetic fixtures to check intended allow and deny cases. Our two-account Supabase checker provides a reproducible starting point in a disposable environment you control. It does not prove every application path is safe.
A careful migration checklist
- Inventory browsers, servers, workers, functions, webhooks and automation that call the project.
- Identify where public keys, privileged keys and user session tokens are used. Do not paste actual credentials into tickets or online decoders.
- Create the appropriate new keys and update callers using current SDK and platform guidance.
- Test normal user flows and unauthorized requests in staging. Verify background work, storage and integrations, not only the homepage.
- Verify that legacy callers have been replaced before deactivating old keys. For an active compromise, agree a containment plan that prioritizes stopping unauthorized access.
- Monitor failures and review the exposed authority. A reversible configuration change is not a reason to casually reactivate a compromised credential.
The new keys are opaque API keys, not user JWTs. Do not assume an integration that previously accepted a legacy key in a bearer-token field will accept a new one unchanged. Check the current documentation for that caller and its authentication headers.
In particular, do not blindly disable Edge Function JWT verification to make an error disappear. Identify whether the function accepts user tokens, trusted service calls or another signed request, then enforce the corresponding authentication and authorization. A function that responds successfully is not proof that it rejects unauthorized callers.
Check the build that actually shipped
Inspect generated HTML, client bundles and other public build outputs, not only your environment file. A supposedly server-only value can reach a visitor through rendered content or a response even without a public environment-variable prefix.
Our frontend environment-variable lab demonstrates those paths using synthetic values. Never publish real credentials to create a test case.
What developer review adds
A developer connects the key inventory to the data model, account boundaries and privileged execution paths. That means testing whether the right user can perform a necessary action and whether the wrong user is denied, not just finding strings that look like secrets.
See the illustrative audit report for the evidence and remediation format, and the audit cost guide for scoping. Fix implementation is quoted separately from the review. Request a security audit quote.
Sources reviewed for this update: Supabase API keys and migration guidance. Check the current instructions before changing production credentials.
Correct keys are only part of the permission model. Our Supabase RLS field-permission example shows why a customer can own a record without being allowed to set its price or payment status.
Know what needs fixing before you ship.
Get a scoped developer review, evidence-backed findings and remediation guidance, with a free re-review of agreed fixes. Fix implementation is quoted separately.
