---
title: "Supabase anon key vs service role key: hvad åbner de?"
description: "Supabase anon key (publishable key) er kun sikker i browseren bag RLS; service role key (secret key) omgår RLS. Hvor hver hører hjemme, testet lokalt."
url: "https://madsalt.tech/da/blog/supabase-anon-key-vs-service-role-key/"
author: "Denys Zaichenko"
language: "da"
published: 2026-10-25
---

# Supabase anon key vs service role key: hvad åbner de?

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](https://supabase.com/docs/guides/api/api-keys) 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:

![Hvilken Postgres-rolle hver nøgle bliver til. Og om dine RLS-policies ser anmodningen. Publishable key, logget ud: Publishable key → rolle anon → RLS-policies gælder; Publishable key, logget ind: Publishable key + brugertoken → rolle authenticated → RLS-policies gælder; Secret key: Secret key → rolle service_role → RLS omgås.](https://madsalt.tech/charts/da/supabase-anon-key-vs-service-role-key.svg)

*Figur 1. Fra Supabases guide til API-nøgler, kontrolleret på en lokal stack, 23. oktober 2026.*

| 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](https://mattpalmer.io/posts/2025/05/statement-on-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-Agent` og returnerer `401`. Den gamle `service_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.

1. 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.
2. Søg i den byggede JavaScript og i Git-historikken efter `sb_secret_` og `service_role`. Escapes scanning af 5.600 apps lavet med vibe coding fandt [over 400 afslørede hemmeligheder](https://escape.tech/blog/methodology-how-we-discovered-vulnerabilities-apps-built-with-vibe-coding/), de fleste i frontend-bundles.
3. Gennemgå, hvad der ændrede sig, mens den var ude: nye brugere, rolleændringer, slettede rækker.

Det gratis [Supabase sikkerhedstjek](https://madsalt.tech/da/tools/supabase-security-check/) 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](https://madsalt.tech/da/blog/vibe-coding-security-risks/), og den fulde liste, jeg kører på en app, står i min [sikkerhedstjekliste til Lovable-apps](https://madsalt.tech/da/blog/lovable-app-security-checklist/).

Usikker på, hvilken nøgle din app sender ud?

Jeg kigger gerne på den og udveksler erfaringer. Ingen salgstale.

[Kontakt mig](https://madsalt.tech/da/#contact)
