Supabase foundations
Separate public and secret keys
Understand publishable or anonymous client keys, server-only secret keys, JWT context, and why RLS remains mandatory.
9 minute lesson
Every Supabase project ships with two kinds of API credentials, and mixing them up is the fastest way to turn a small bug into a data breach.
The publishable key (named sb_publishable_...; older projects call it the anon key) is safe to ship in a browser or mobile app. It identifies your Supabase project; it does not grant unrestricted database authority by itself. Requests made with it run through Row Level Security, and the user session adds identity claims on top.
The secret key (sb_secret_..., or the legacy service_role JWT) is a different animal. Clients created with it bypass Row Level Security entirely:
import { createClient } from '@supabase/supabase-js'
// server-side code only
const admin = createClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_SECRET_KEY
)
const { data } = await admin.from('notes').select()
console.log(data.length)
// every note from every user — no policy applied
That power is why secret keys must never reach a browser, mobile bundle, log line, or public repository. A leaked privileged key is an authorization incident: every RLS policy you wrote stops protecting anything until you rotate the key.
Verify what your build ships
Do not trust the mental model — check the artifact. After building your frontend:
grep -R "sb_secret" dist/
# (no output — this must find nothing)
grep -R "service_role" dist/
# (no output)
If either command prints a match, a privileged key made it into client code. Rotate it in the dashboard under Settings → API Keys immediately, then fix the import that leaked it. Rotation is not optional after exposure; the key does not expire on its own.
The inventory habit
Take a small app and inventory every environment variable it uses. For each one, write three facts: can it enter client code, where does the server-only copy live, and how do you rotate it. The project URL and the publishable key can be public. The database password, the secret key, and SMTP credentials stay server-side, in your deployment platform’s secret store.
One warning to keep intact: the publishable key is only safe to expose while RLS is enabled and correct on every exposed table. A public key plus an unprotected table is a public table.
Lesson completed