TL;DR
Anon key, som nu hedder publishable key, er lavet til at være offentlig: den svarer til rollen anon eller authenticated, og dine RLS-policies afgør, hvad den ser. Service role key, nu secret key, svarer til service_role, som omgår RLS helt. På min lokale testtabel med RLS slået til og ingen policy fik publishable key 0 rækker og secret key alle 3. Læg publishable key i browseren, hold secret key på en server, og rotér den, hvis den nogensinde er sluppet ud.
Jeg er Denys, fullstack- og AI-ingeniør. En lækket secret key er det første, jeg leder efter, når jeg overtager en Supabase-app, for med den er alle andre beskyttelser pynt. Denne artikel forklarer, hvad hver nøgle åbner, med de anmodninger, jeg kørte for at kontrollere det.
Hvad er Supabase anon key?
Anon key identificerer din app, ikke din bruger. Hver anmodning fra en browser eller en mobilapp bærer den, så den må være offentlig: alle kan læse den i sidens kilde. En anmodning med kun denne nøgle kører som Postgres-rollen anon. Når en bruger logger ind gennem Supabase Auth, rejser den samme nøgle med brugerens token, og anmodningen kører som authenticated. Dine RLS-policies er skrevet til de to roller.
Supabase omdøber nøglerne. Guiden til API-nøgler kalder de nye publishable (sb_publishable_…) og secret (sb_secret_…) og udfaser de gamle JWT-baserede nøgler anon og service_role inden udgangen af 2026. Rollerne bag dem forbliver de samme.
| Nøgle | Gammelt navn | Postgres-rolle | Gælder RLS? | Hvor den hører hjemme |
|---|---|---|---|---|
Publishable sb_publishable_… |
anon-nøglen |
anon, eller authenticated med brugerens token |
Ja | Browser, mobilapp, alt hvad du udsender |
Secret sb_secret_… |
service_role-nøglen |
service_role |
Nej, rollen har BYPASSRLS |
Kun server, Edge Function, cron-job |
Er det sikkert at eksponere Supabase anon key?
Ja, hvis hver tabel, hvert view og hver funktion, den kan nå, er beskyttet. Selve nøglen giver intet særligt; rettighederne og policies i dit schema afgør alt. Jeg kontrollerede det på en lokal Supabase (CLI 2.109.1, Postgres 17.6) med én tabel med tre falske ordrer:
| Tabellens tilstand | Publishable key | Secret key |
|---|---|---|
| RLS slået fra | Alle 3 rækker, og en indsættelse gav 201 Created |
Alle 3 rækker |
| RLS slået til, ingen policy | [] |
Alle 3 rækker |
RLS slået til, policy using (true) |
Alle 3 rækker | Alle 3 rækker |
Ingen rettighed til anon |
42501 permission denied, med et hint der nævner den manglende GRANT |
Alle 3 rækker |
Publishable key er altså lige så sikker som din svageste tabel. En tabel uden RLS, eller med en policy der tillader hver række, kan læses af alle, der åbner DevTools. Det er hullet bag CVE-2025-48757, hvor 170 af 1.645 Lovable-showcase-apps udleverede data til den offentlige nøgle.
Hvad er service role key, og hvorfor er den farlig?
Secret key er hovednøglen. Den kører som service_role, som har attributten BYPASSRLS, så ingen policy, du skriver, gælder nogensinde for den. I sidste kolonne i tabellen ovenfor læste den alle tre rækker i enhver tilstand. Supabases guide angiver, hvor den hører hjemme: servere, der selv laver autorisationstjek, Edge Functions, baggrundsjobs og admin-værktøjer. To detaljer fra guiden betyder noget i praksis:
- Den nye secret key afviser anmodninger fra browsere: Supabase matcher
User-Agentog returnerer401. Den gamleservice_role-JWT har ikke sådan et tjek, så en lækket gammel nøgle virker fra hvor som helst. Min lokale stack, som ikke har et sådant gateway-tjek, svarede et script med secret key med alle 3 rækker. - En secret key omgår kun RLS, når anmodningen ikke bærer en brugers token. Med en indlogget brugers token kører anmodningen under den brugers policies.
En Edge Function, der bruger secret key, skal selv tjekke, hvem der kalder, og filtrere efter ejer eller virksomhed, fordi intet under den gør det.
Hvor finder du nøglerne?
I Dashboard åbner du dit projekts Connect-dialog for URL og publishable key, eller Settings → API Keys for alle nøgler, de gamle inklusive. Lokalt skriver supabase start og supabase status en publishable key og en secret key ud. Hold dem i miljøvariabler: i Next.js må kun publishable key have præfikset NEXT_PUBLIC_, fordi bundleren sender alt med det præfiks til browseren.
Hvad gør du, hvis service role key lækkede?
Betragt den som kompromitteret: hver række i hver tabel kunne læses og skrives af den, der fandt den.
- Opret en ny secret key, flyt dine servere over på den, og slet den lækkede. Hvis lækagen var en gammel
service_role-nøgle, er vejen ud at skifte til de nye nøgler: opret en publishable og en secret key, skift appen over, og deaktivér derefter de gamle nøgler i Settings → API Keys, hvor de ellers forbliver gyldige. - Søg i den byggede JavaScript og i Git-historikken efter
sb_secret_ogservice_role. Escapes scanning af 5.600 apps lavet med vibe coding fandt over 400 afslørede hemmeligheder, de fleste i frontend-bundles. - Gennemgå, hvad der ændrede sig, mens den var ude: nye brugere, rolleændringer, slettede rækker.
Det gratis Supabase sikkerhedstjek læser ikke din frontend, men det læser databasesiden af det samme problem: roller, der omgår RLS, tabeller med RLS slået fra, policies der tillader hver række, og kolonner der ligner følsomme data og kan læses af anonyme besøgende. Hvordan du tjekker, hvad din offentlige nøgle når i praksis, står i vibe coding security risks, og den fulde liste, jeg kører på en app, står i min sikkerhedstjekliste til Lovable-apps.
Usikker på, hvilken nøgle din app sender ud?
Jeg kigger gerne på den og udveksler erfaringer. Ingen salgstale.
Kontakt mig