1.Why the public key is meant to be seen
Every request to your Supabase project carries an API key (a code that tells Supabase which app is calling). Your app’s browser code needs one to reach the database, and anyone can read browser code. So Supabase gives you a public key for this job. Its docs picture it as a key “taped to the front door” that only opens the lobby.
What keeps the rest of the building shut is row level security, or RLS. A request with the public key and no sign-in runs as the anon role (Supabase’s name for a visitor who is not signed in). A signed-in user runs as authenticated. Your RLS rules say what each role may read, add, change and delete. A table with no rules is the problem, not the key.
2.The four kinds of Supabase key
Supabase’s API keys page lists two current keys and two older (“legacy”) ones:
| Key | What it looks like | Where it belongs | What it can reach |
|---|---|---|---|
| Publishable key | Starts with sb_publishable_ | Browser, mobile app, any code you ship | Only what your RLS rules allow |
| anon key (legacy) | A long code that starts with eyJ | Same as the publishable key | Only what your RLS rules allow |
| Secret key | Starts with sb_secret_ | Only server code you control, never the browser | All your data. It skips every RLS rule |
| service_role key (legacy) | A long code that starts with eyJ | Same as the secret key | All your data. It skips every RLS rule |
Watch the names in your settings file (.env). A name that starts with VITE_ or NEXT_PUBLIC_ goes into the browser code. Supabase warns never to give a server-only key such a name, and Lovable’s docs say VITE_SUPABASE_PUBLISHABLE_KEY is safe to be public.
Supabase is deprecating (phasing out) the anon and service_role keys by the end of 2026, and asks you to use publishable and secret keys instead (API keys). If your app still uses a key that starts with eyJ, plan the move now.
3.A real example: a safe key and an open table
On 1 November 2026, LidTight ran its free check on Tidybook, our own demo app built with Lovable. Its database is Lovable Cloud, Lovable’s built-in backend, which is built on Supabase. The check read the 27 files (738 KB) of code that every visitor downloads. These lines are from that run:
- “Looking for secret keys: none found”
- “CRITICAL Anyone can read your reviews table: 12 rows, with first_name, email, phone”
- “No sign-in needed. A stranger can download these records with one request.”
The public key was in the code, as it should be, and the check did not report it. Of the two tables, bookings and reviews, only reviews was open to strangers (“1 open to anyone”). Same key, two tables, two results. The rules made the difference, not the key.
Reviews are often meant to be public. Email addresses and phone numbers are not. RLS decides which rows someone can read, not which columns. So a table that strangers may read should hold only details you are happy to publish. Keep email and phone in a separate table with its own rules.
4.Check which key your live app ships
- Open your live app, not your project files, in Chrome. Click through a page that shows data, so its code loads.
- Open Chrome’s developer tools: Cmd + Option + I on a Mac, Ctrl + Shift + I on Windows (Chrome docs).
- Open the search across all loaded files: Cmd + Option + F on a Mac, Ctrl + Shift + F on Windows (Chrome docs).
- Search for sb_secret_. A match followed by a long random code is a leaked secret key. Go to “If a secret key leaked” below. The bare text sb_secret_ with nothing after it is not a key.
- Search for sb_publishable_. A match followed by a long code is your public key. That is expected.
- Search for eyJ. Both legacy keys start this way, so you cannot tell them apart by eye. Compare each long match with the keys under Settings > API Keys in your Supabase dashboard. The anon key is fine. The service_role key is a leak.
The free check on this site does the same search in your live app’s code. It looks for Supabase secret keys and reads the role written inside each legacy key, so it can tell an anon key from a service_role key. It does not report public keys, because they belong there.
5.Check that every table has rules
With your own Supabase project, use Supabase’s Security Advisor, which is built into Supabase. It checks your database setup for common problems. Supabase notes that some findings may be intentional, so read each one.
- Open the Security Advisor in your Supabase dashboard.
- Fix every “Table publicly accessible” finding. It means RLS is off on a table in the public schema (the part of the database your app’s API exposes). Supabase says that anyone with your project address can then read, edit and delete all data in that table.
- Fix every “Sensitive data publicly accessible” finding: a table with RLS off and columns whose names look like passwords, tokens or ID numbers. Its list of names does not include email or phone, so do not count on it for those.
- Read every “Security policy allows unrestricted access” warning. It means a rule such as USING (true) lets everyone in that role reach every row. Keep such a rule only for data that is meant to be public.
On Lovable Cloud, open More > Database, select Manage, then Policies (Lovable docs). Each rule shows its action (SELECT means reading), who it covers (anon means visitors who are not signed in) and its condition. To change a rule, ask Lovable in the project chat.
To see the result as a stranger would, run the free check. It counts the rows a stranger can read in each table and keeps none of them. It cannot see your rules, and it does not test what a signed-in user can read: see Can one customer see another customer’s data?
6.Close an open table
In the SQL Editor of your Supabase dashboard, turn on RLS for the table. Supabase’s guide explains that the public key then reads nothing from it until you add rules. Then add one rule per action: read, add, change, delete. This example, based on the guide, lets each signed-in user read only their own profile:
-- Turn on row level security
alter table public.profiles enable row level security;
-- A rule for reading: each signed-in user sees only their own row
-- (the table needs a user_id column with the owner id)
create policy "Users can view their own profile"
on public.profiles for select
to authenticated
using ( (select auth.uid()) = user_id );The guide also asks you to take back the default grants (permissions each role gets on a new table), because rules do not remove them. It shows how to test each table too.
On Lovable, ask in the project chat, for example: “Turn on row level security for every table. Add a rule for each action: who may read, add, change and delete. Keep customers’ email and phone numbers in a table that strangers cannot read.” Then check again.
7.If a secret key leaked: rotate it
A secret or service_role key skips every RLS rule, and Supabase says that exposing one puts all of your project’s data at risk. The newer secret keys refuse to work in a browser, but an attacker can still use them from other tools. So deleting the key from your code is not enough. You must rotate it: make a new key and turn the old one off. Supabase’s rotation guide gives these steps:
- Fix the cause first. Move the code that uses the key to your server or an Edge Function (server code that never reaches the browser), so the new key cannot leak the same way. If someone is already using the leaked key, retire it at once (step 5).
- Create a new secret key under Settings > API Keys in your Supabase dashboard.
- Put the new key everywhere your server code used the old one.
- If the leaked key was a legacy service_role key, also switch your browser code from the anon key to a publishable key. Retiring the leaked key turns off both legacy keys.
- Retire the leaked key: delete a secret key, or deactivate the legacy keys. Deleting cannot be undone.
- For a legacy service_role key, also revoke the legacy JWT secret (the value that signed the legacy keys). Supabase’s guide links to the steps.
On Lovable Cloud, Lovable manages the SUPABASE_ keys, and its Secrets screen cannot change them (Lovable docs). If one is in your browser code, ask Lovable in the project chat to move that code to an Edge Function, and ask Lovable support how to replace the key.
For a leaked AI key, see Someone is running up your AI bill. For everything to check before launch, see the launch security checklist.