Is the Supabase anon key safe to expose?
Short answer: Yes. The Supabase anon key (now called the publishable key) is meant to be public. It ships in your web or mobile app, and anyone can read it. It isn't what protects your data. Row Level Security (RLS) is, along with the table permissions you set. The key you must never expose is the service_role (or secret) key.
Last checked: Oct 17, 2026 · Source: Supabase docs: API keys
Why the anon key is public by design
Supabase gives every project two kinds of API keys:
| Key | Old name | New format | Where it belongs |
|---|---|---|---|
| Publishable key | anon | sb_publishable_... | Anything you ship: browser, mobile app, scripts |
| Secret key | service_role | sb_secret_... | Only code you control: your server, Edge Functions, cron jobs |
Any key inside a web page or app can be found by anyone who opens the browser's developer tools. Supabase plans for that. The publishable/anon key only identifies which app is calling. It doesn't prove who the user is, and it doesn't unlock your data by itself.
When a request comes in with that key, Supabase treats it as the anon role (signed-out visitor) or, if the user is logged in, the authenticated role. Your RLS policies decide what those roles can see and change.
Heads-up on names: Supabase says it is deprecating the legacy anon and service_role keys by the end of 2026 in favor of publishable and secret keys. The rules on this page are the same for both: the publishable/anon key can be public, and the secret/service_role key must stay private.
What actually protects your data: RLS
Row Level Security is a Postgres feature that you turn on per table and then write rules (called policies) for. Think of a policy as an automatic WHERE clause added to every query, for example "users can only see rows where user_id is their own ID."
You control this setting. Supabase's own docs put the stakes plainly: a table in an exposed schema (like public) without RLS is readable and writable by any role that has been granted access to it. With RLS on and the right policies, the public key can only reach what your policies allow.
New to RLS? Start with our beginner's guide.
Three things have to be right together:
- RLS is enabled on every table in
public(and any other schema your API exposes). - Each table has policies that match what your app is supposed to allow, ideally one per action (select, insert, update, delete).
- Grants are only what's needed. Grants decide whether a role can touch a table at all; policies decide which rows. Supabase recommends setting both.
If you built your app with Lovable or another AI builder, the same applies: RLS is a setting on your Supabase project, and you (the builder) decide whether it's on and what the policies say. AI tools can write policies for you, but it's worth reading them before you rely on them.
The key you must never expose: service_role / secret
The service_role key (and the newer secret key) bypasses every RLS policy. It's meant for trusted server code that runs its own checks. If it ends up in your frontend, anyone who finds it gets full access to your project's data, no matter how good your policies are.
Keep it out of:
- Browser code, mobile apps and anything you ship to users
- Environment variables your framework exposes to the browser (for example names starting with
NEXT_PUBLIC_orVITE_) - Your Git repo, chat messages and logs
Supabase's newer secret keys add a guardrail: they're rejected (HTTP 401) when used from a browser. That helps, but it's not a reason to put one there. If a secret or service_role key has leaked, Supabase's docs describe how to create a new key, swap it in everywhere, then retire the old one.
How to check your own app (5 steps)
These checks run inside your own Supabase project and your own code. Only check projects you own or have permission to test.
1. Run Supabase's Security Advisor. In your Supabase dashboard, open the Security Advisor. It flags common problems, including tables in public with RLS turned off and views that bypass RLS. Review each finding before you dismiss it.
2. List which of your tables have RLS on. In your project's SQL Editor:
select tablename, rowsecurity as rls_enabled from pg_tables where schemaname = 'public' order by tablename;
Any row with rls_enabled = false needs attention.
3. Read your policies. Still in the SQL Editor:
select tablename, policyname, roles, cmd, qual, with_check from pg_policies where schemaname = 'public' order by tablename;
Look for policies that allow everything (like using (true)) on tables that hold private data. That pattern is fine for truly public data, like a product list, and risky for anything personal.
4. Check what the public roles are granted.
select table_name, grantee, privilege_type
from information_schema.role_table_grants
where table_schema = 'public'
and grantee in ('anon', 'authenticated')
order by table_name, grantee;Signed-out visitors (anon) should only have what they truly need, often just select on public tables, or nothing at all.
5. Make sure no secret key is in your frontend. Search your own codebase and build output for service_role, SERVICE_ROLE, sb_secret_ and any secret key variable names. The only Supabase key in client code should be the publishable/anon key.
Fixing a table without RLS (adapt to your app, and add policies right after, or your app will stop reading that table):
alter table public.your_table enable row level security; create policy "Users can view their own rows" on public.your_table for select to authenticated using ( (select auth.uid()) = user_id );
Supabase's RLS guide has examples for insert, update and delete, plus how to test policies with supabase test db.
Want a quick outside check too? Run a free Greenlight scan to check the basics (HTTPS, security headers, exposed keys). It's not a full security audit.
Paid reports: coming soon.
Common myths
- "My anon key is in my JavaScript, so I've been hacked." No. It's supposed to be there. What matters is whether RLS and your policies limit what it can reach.
- "I should hide the anon key in an environment variable." Using an env variable is tidy, but if the key reaches the browser, it's still public. That's expected for this key.
- "Rotating the anon key fixes an exposed table." It doesn't fix the cause. The new public key would be just as visible. Turn on RLS and fix the policies.
- "RLS is on, so I'm done." RLS with no policies blocks the public key from that table entirely (your app may break), and an overly broad policy can still allow too much. Read the policies.
FAQ
Is it safe to put the Supabase anon key in my frontend code?
Yes. Supabase designed the anon (publishable) key for browsers and apps. Your data's protection comes from Row Level Security policies and table grants, which you need to set up correctly.
What's the difference between the anon key and the service_role key?
The anon key runs requests as a signed-out or signed-in user and is limited by RLS. The service_role key bypasses RLS and has full access. It belongs only on your server.
What happens if my service_role key is exposed?
Treat it as an emergency. Anyone with it can bypass your RLS policies. Fix how it leaked, create a new secret key in Supabase, replace it everywhere, then retire the old key, following Supabase's API keys guide.
What are publishable and secret keys?
They're Supabase's newer key types. The publishable key (sb_publishable_...) replaces anon, and the secret key (sb_secret_...) replaces service_role. Supabase says the legacy keys are being deprecated by the end of 2026.
Do I need RLS if my app has a login?
Yes. A login decides who the user is. RLS decides which rows that user can see. Without RLS, a signed-in user could reach other users' rows through the API.
Does the October 30, 2026 Supabase change affect this?
That change stops new tables in public from being exposed to the API automatically; you'll need to add grants. RLS still works the same way, and you still need it. See our Oct 30 explainer.
Does Greenlight check my RLS policies?
No. Greenlight's free scan checks the basics from the outside (HTTPS, security headers, exposed keys). It doesn't log into your Supabase project or read your policies, so use the Security Advisor and the steps above for that.
Sources
- Supabase docs: API keys
- Supabase docs: Row Level Security
- Supabase docs: Securing your API
- Supabase docs: Advisors (Security Advisor)
- Supabase docs: Production checklist
Greenlight is independent and not affiliated with or endorsed by Supabase or Lovable. Product names are used only to describe compatibility. This page is educational, not a security audit or a security guarantee.