---
title: "Slik aktiverer du RLS i Supabase og hva du får tilbake"
description: "Slik aktiverer du Supabase RLS fra dashbordet eller med SQL, testet lokalt, med hva den offentlige nøkkelen, to brukere og den hemmelige nøkkelen får."
url: "https://madsalt.tech/no/blog/how-to-enable-rls-in-supabase/"
author: "Denys Zaichenko"
author_url: "https://madsalt.tech/no/about/"
language: "no"
published: 2026-11-04
---

# Slik aktiverer du RLS i Supabase og hva du får tilbake

TL;DR

Aktiver RLS i Supabase med én setning per tabell, `alter table public.todos enable row level security;`, eller med valget "Enable RLS" i dashbordet. Tabeller laget i SQL-editoren eller av en migrering får det ikke som standard. Rett etter at du har aktivert det, blir tabellen stille snarere enn høylytt. I min lokale test fikk den offentlige nøkkelen og to innloggede brukere `200 []` på select, update og delete, og bare insert feilet med `42501`. Den hemmelige nøkkelen så fortsatt alle 3 rader. En vanlig view over tabellen ga fortsatt alle 3 rader til den offentlige nøkkelen. Siden 30. oktober 2026 trenger en ny tabell dessuten en grant før noe når den, så aktiver RLS og skriv policyer i samme migrering som granten.

Jeg driver en gratis [Supabase security checker](https://madsalt.tech/no/tools/supabase-security-check/), og "RLS disabled" er funnet jeg ser forklart dårligst. De fleste guider sier at etter at du har aktivert RLS, "blir tabellen utilgjengelig". Det stemmer for lesing og er misvisende for skriving. Så jeg bygde én tabell på en lokal Supabase-stack og sendte alle slags forespørsler til den, som den offentlige nøkkelen, som to innloggede brukere og som den hemmelige nøkkelen, etter hvert trinn nedenfor.

## Hva er RLS i Supabase?

RLS (row-level security) er en Postgres-funksjon som filtrerer rader per forespørsel. Supabase gjør hver forespørsel fra `supabase-js` om til en databasespørring som kjører som en rolle: `anon` for den offentlige nøkkelen (anon, publishable), `authenticated` for en innlogget bruker. Med RLS på sjekker Postgres policyene dine for hver rad og returnerer, endrer eller sletter bare radene en policy tillater. Med RLS av når hver rolle med en grant på tabellen alle radene.

Den hemmelige nøkkelen (service role) er annerledes. Rollen har `BYPASSRLS`, så RLS gjelder aldri for den. Derfor hører den bare hjemme på en server. Forskjellen mellom de to nøklene står i [Supabase anon key vs service role key: hva hver åpner](https://madsalt.tech/no/blog/supabase-anon-key-vs-service-role-key/).

## Hvordan aktiverer du RLS i Supabase?

Tre måter, avhengig av hvordan tabellen ble laget:

- **Når du lager en tabell i Table Editor**, la "Enable Row Level Security (RLS)" stå avkrysset. I Supabases [dashbordkode](https://github.com/supabase/supabase/commit/33bd798d142183e162c25debcc50c8c711e68f66) er det merket "Recommended", og slår du det av, vises en advarsel om at tabellen blir offentlig lesbar og skrivbar.
- **For en eksisterende tabell** sier Supabases [guide for å sikre API-et](https://supabase.com/docs/guides/api/securing-your-api): gå til Database, deretter Policies, og velg "Enable RLS" på tabellen.
- **I SQL**, i SQL-editoren eller en migrering:

```sql
alter table public.todos enable row level security;
```

Supabases guide er tydelig på at tabeller laget i dashbordet har RLS på som standard, og at tabeller laget i SQL-editoren eller med et annet verktøy ikke har det. Bygger du skjemaet med migreringer eller et AI-verktøy, sjekk hver tabell.

## Hva skjer rett etter at du har aktivert RLS?

Ingenting gir feil unntatt insert. Jeg laget `public.todos` med en eierkolonne (`user_id uuid default auth.uid()`), ga den grants til API-rollene slik eldre prosjekter har det og la til tre rader: to eid av bruker A og én av bruker B. Deretter aktiverte jeg RLS uten policy:

| Forespørsel     | Offentlig nøkkel | Bruker A        | Bruker B        | Hemmelig nøkkel   |
| --------------- | ---------------- | --------------- | --------------- | ----------------- |
| Select          | 200, 0 rader     | 200, 0 rader    | 200, 0 rader    | 200, 3 rader      |
| Insert egen rad | 401, feil 42501  | 403, feil 42501 | 403, feil 42501 | 201, rad satt inn |
| Update en rad   | 200, 0 rader     | 200, 0 rader    | 200, 0 rader    | 200, 1 rad        |
| Delete en rad   | 200, 0 rader     | 200, 0 rader    | 200, 0 rader    | 200, 1 rad        |

Insert-feilen lyder `new row violates row-level security policy`. Update og delete svarer `200` med en tom liste, så en app som ikke sjekker de returnerte radene, melder «lagret» når ingenting ble lagret. Les skrivingene dine tilbake etter at du har aktivert RLS, eller be om et antall med `Prefer: count=exact`.

Før RLS, med de samme grantene, kunne den offentlige nøkkelen lese alle 3 rader, sette inn, og oppdatere eller slette hvilken som helst rad. Bruker A kunne redigere og slette bruker Bs rad og gi bort sine egne rader til B.

## Hvordan gjør du tabellen brukbar igjen?

Skriv en policy per operasjon. Det vanlige settet for egne rader:

```sql
create policy "own select" on public.todos for select to authenticated
  using ((select auth.uid()) = user_id);
create policy "own insert" on public.todos for insert to authenticated
  with check ((select auth.uid()) = user_id);
create policy "own update" on public.todos for update to authenticated
  using ((select auth.uid()) = user_id) with check ((select auth.uid()) = user_id);
create policy "own delete" on public.todos for delete to authenticated
  using ((select auth.uid()) = user_id);
```

Med disse så bruker A sine 2 rader og bruker B sin 1. Den offentlige nøkkelen så fortsatt 0. Da A prøvde å sette inn en rad eid av B, eller å flytte sin egen rad til B, ble svaret `403, 42501`. Den avvisningen kommer fra `with check` på update. Da A prøvde å oppdatere eller slette Bs rad, ble svaret `200, 0 rader`. Flere mønstre (offentlige profiler, team, MFA) står i [Supabase RLS policy-eksempler, testet via API-et](https://madsalt.tech/no/blog/supabase-rls-policy-examples/).

En detalj fra den hemmelige nøkkelen: en rad den satte inn, fikk `user_id = null`, fordi `auth.uid()` ikke har noen bruker bak den nøkkelen. RLS ble hoppet over, men standardverdien gjorde ikke det kolonnenavnet tilsier.

## Hva leste den offentlige nøkkelen etter hvert trinn?

![Rader den offentlige nøkkelen leste, av 3. Én Supabase-tabell med 3 rader, etter hvert trinn. Ny tabell, ingen grant, RLS av (feil 42501): 0; Grant lagt til, RLS av: 3; RLS på, ingen policy: 0; RLS på, policyer for egne rader: 0; Vanlig view over tabellen: 3; View med security_invoker: 0.](https://madsalt.tech/charts/no/how-to-enable-rls-in-supabase.svg)

*Figur 1. Lokal Supabase-stack (CLI 2.109.1, Postgres 17.6), 28. oktober 2026.*

To trinn lekker alt: en grant uten RLS, og en vanlig view over en tabell med riktige policyer. De neste to avsnittene forklarer begge.

## Trenger du fortsatt RLS etter grant-endringen 30. oktober?

Ja. Siden 30. oktober 2026 gir Supabase ikke lenger nye tabeller i `public` automatiske grants til API-rollene, verken på nye eller eksisterende prosjekter. Min lokale stack oppfører seg allerede slik. En nylaget tabell med RLS av svarte `42501` til hver rolle, også den hemmelige nøkkelen, så ingenting lekket. Detaljene står i [Supabase 30. oktober: hva som knekker og hvordan sjekke](https://madsalt.tech/no/blog/supabase-october-30-grant-change/).

Men granten kommer tilbake så snart appen trenger tabellen, og fra da av er RLS det eneste som står mellom den offentlige nøkkelen og hver rad. Så legg alt i én migrering, i denne rekkefølgen:

```sql
create table public.todos (...);
alter table public.todos enable row level security;
create policy "own select" on public.todos ...;
grant select, insert, update, delete on table public.todos to authenticated;
```

Gi grants bare til rollene som trenger tabellen. Da jeg trakk tilbake alt fra `anon`, endret den offentlige nøkkelens select seg fra `200 []` til `401, 42501`. Granten er den første låsen, RLS den andre.

## Hvorfor lekker en view fortsatt rader?

Fordi en view kjører med eierens rettigheter, og i Supabase er det `postgres`, som omgår RLS. Med policyene for egne rader på plass på `todos` ga en vanlig `create view public.todos_view as select * from public.todos` alle 3 rader til den offentlige nøkkelen og til bruker B.

Laget på nytt `with (security_invoker = true)` ga den samme viewen 0 rader til den offentlige nøkkelen, 2 til A og 1 til B, nøyaktig som tabellen:

```sql
create view public.todos_view with (security_invoker = true) as
  select * from public.todos;
```

Supabases Advisor flagger den vanlige typen som `security_definer_view`; hva det betyr og hvordan du fikser det, står i [notatet om Supabase security definer view](https://madsalt.tech/no/notes/supabase-security-definer-view/).

## Hvordan aktiverer du RLS på hver ny tabell automatisk?

Med en event trigger. Supabases [guide til event triggers](https://supabase.com/docs/guides/database/postgres/event-triggers) gir en funksjon `rls_auto_enable()` og en trigger `ensure_rls` som kjører etter `create table`, `create table as` og `select into` i `public`. Jeg installerte den slik den er publisert og fikk:

- En tabell laget etterpå med `create table` hadde RLS på uten noen `alter`. Den offentlige nøkkelen fikk `200 []` på select og `401` på insert.
- En tabell laget med `create table as select` hadde også RLS på.
- En tabell laget før triggeren forble av. Triggeren virker ikke tilbakevirkende.

Uten triggeren hadde en andre tabell, laget ved siden av den beskyttede, RLS av, og når den fikk en grant, kunne den offentlige nøkkelen lese og skrive den fritt. Den dekker dessuten bare `public`; andre eksponerte skjemaer trenger sin egen linje i funksjonen.

## Hjelper FORCE ROW LEVEL SECURITY?

Ikke for rollene du bekymrer deg for. `alter table ... force row level security` får RLS til å gjelde også tabellens eier. I Supabase har både `postgres` og `service_role` `BYPASSRLS`, så etter `force` talte eieren fortsatt 3 rader, den hemmelige nøkkelen så fortsatt alt, og en view eid av `postgres` lekket fortsatt. Det endret bare noe for en eierrolle jeg laget uten `BYPASSRLS`: 2 rader før, 0 etter.

## Hvordan sjekker du ditt eget prosjekt?

- List i SQL-editoren tabellene i `public` med RLS av:

```sql
select c.relname as table_name
from pg_class c
join pg_namespace n on n.oid = c.relnamespace
where n.nspname = 'public'
  and c.relkind in ('r', 'p')
  and not c.relrowsecurity
order by 1;
```

- Advisor i dashbordet rapporterer det samme som `rls_disabled_in_public`; hva den feilen betyr, står i [notatet om RLS disabled in public](https://madsalt.tech/no/notes/supabase-rls-disabled-in-public/).
- Den gratis [Supabase security check](https://madsalt.tech/no/tools/supabase-security-check/) leser prosjektet ditt skrivebeskyttet og lister tabeller med RLS av som API-et kan nå, views som omgår RLS og policyer som slipper inn alle, med SQL for å fikse hver.
- En skanner kan ikke vite hvilke rader som tilhører hvem. For å bevise det må du sende forespørsler som to brukere, som ovenfor. Hele metoden for en app med roller står i [Test Supabase RLS: 30 av 87 tilganger gjorde ingenting](https://madsalt.tech/no/blog/how-to-test-supabase-rls/).

## Slik testet jeg

- Supabase CLI 2.109.1 på en bærbar: Postgres 17.6, PostgREST 14.14, Auth 2.192.0. To brukere logget inn med passord, pluss de lokale publishable og secret keys.
- Én tabell, `public.todos`, tilbakestilt til de samme 3 radene før hver forespørsel. Hvert trinn ble utført som SQL, og hver forespørsel gikk over REST-API-et, med statuskode og body notert.
- Grants for trinn 2 til 5 ble lagt til for hånd, for å tilsvare et prosjekt laget før 30. oktober 2026.

**Begrensninger.** Én lokal stack, oppdiktede data, 28. oktober 2026. Dashbord-trinnene er sitert fra Supabases dokumentasjon, ikke klikket gjennom. Tabeller laget av dashbordets egen rolle kan få andre standard grants. Det testet jeg ikke, og heller ikke Storage, Realtime eller GraphQL.

Usikker på om tabellene dine er låst?

Jeg ser gjerne på et skjema sammen med deg. Uten salgstale.

[Ta kontakt](https://madsalt.tech/no/#contact)
