---
title: "Så aktiverar du RLS i Supabase och vad du får tillbaka"
description: "Så aktiverar du Supabase RLS i dashboarden eller med SQL, testat lokalt, med vad den publika nyckeln, två användare och den hemliga nyckeln får."
url: "https://madsalt.tech/sv/blog/how-to-enable-rls-in-supabase/"
author: "Denys Zaichenko"
author_url: "https://madsalt.tech/sv/about/"
language: "sv"
published: 2026-11-04
---

# Så aktiverar du RLS i Supabase och vad du får tillbaka

Kort sagt

Aktivera RLS i Supabase med en sats per tabell, `alter table public.todos enable row level security;`, eller med alternativet "Enable RLS" i dashboarden. Tabeller som skapas i SQL-editorn eller av en migrering får det inte som standard. Direkt efter att du aktiverat det blir tabellen tyst snarare än högljudd. I mitt lokala test fick den publika nyckeln och två inloggade användare `200 []` på select, update och delete, och bara insert misslyckades med `42501`. Den hemliga nyckeln såg fortfarande alla 3 rader. En vanlig vy över tabellen gav fortfarande alla 3 rader till den publika nyckeln. Sedan den 30 oktober 2026 behöver en ny tabell dessutom ett grant innan något når den, så aktivera RLS och skriv policyer i samma migrering som granten.

Jag driver en gratis [Supabase security checker](https://madsalt.tech/sv/tools/supabase-security-check/), och "RLS disabled" är det fynd jag ser förklarat sämst. De flesta guider säger att efter att du aktiverat RLS "blir tabellen oåtkomlig". Det stämmer för läsning och är missvisande för skrivning. Så jag byggde en tabell på en lokal Supabase-stack och skickade alla slags förfrågningar till den, som den publika nyckeln, som två inloggade användare och som den hemliga nyckeln, efter varje steg nedan.

## Vad är RLS i Supabase?

RLS (row-level security) är en Postgres-funktion som filtrerar rader per förfrågan. Supabase gör varje förfrågan från `supabase-js` till en databasfråga som körs som en roll: `anon` för den publika nyckeln (anon, publishable), `authenticated` för en inloggad användare. Med RLS på kontrollerar Postgres dina policyer för varje rad och returnerar, ändrar eller tar bort bara de rader en policy tillåter. Med RLS av når varje roll med ett grant på tabellen alla rader.

Den hemliga nyckeln (service role) är annorlunda. Dess roll har `BYPASSRLS`, så RLS gäller aldrig för den. Därför hör den bara hemma på en server. Skillnaden mellan de två nycklarna finns i [Supabase anon key vs service role key: vad var och en öppnar](https://madsalt.tech/sv/blog/supabase-anon-key-vs-service-role-key/).

## Hur aktiverar du RLS i Supabase?

Tre sätt, beroende på hur tabellen skapades:

- **När du skapar en tabell i Table Editor**, låt "Enable Row Level Security (RLS)" vara ibockat. I Supabases [dashboardkod](https://github.com/supabase/supabase/commit/33bd798d142183e162c25debcc50c8c711e68f66) är det markerat "Recommended", och slår du av det visas en varning om att tabellen blir publikt läsbar och skrivbar.
- **För en befintlig tabell** säger Supabases [guide för att säkra API:t](https://supabase.com/docs/guides/api/securing-your-api): gå till Database, sedan Policies, och välj "Enable RLS" på tabellen.
- **I SQL**, i SQL-editorn eller en migrering:

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

Supabases guide är tydlig med att tabeller som skapas i dashboarden har RLS på som standard, och att tabeller som skapas i SQL-editorn eller med ett annat verktyg inte har det. Bygger du ditt schema med migreringar eller ett AI-verktyg, kontrollera varje tabell.

## Vad händer direkt efter att du aktiverat RLS?

Inget ger fel utom insert. Jag skapade `public.todos` med en ägarkolumn (`user_id uuid default auth.uid()`), gav den grants till API-rollerna på samma sätt som äldre projekt och lade till tre rader: två ägda av användare A och en av användare B. Sedan aktiverade jag RLS utan policy:

| Förfrågan       | Publik nyckel  | Användare A    | Användare B    | Hemlig nyckel    |
| --------------- | -------------- | -------------- | -------------- | ---------------- |
| Select          | 200, 0 rader   | 200, 0 rader   | 200, 0 rader   | 200, 3 rader     |
| Insert egen rad | 401, fel 42501 | 403, fel 42501 | 403, fel 42501 | 201, rad infogad |
| 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-felet lyder `new row violates row-level security policy`. Update och delete svarar `200` med en tom lista, så en app som inte kontrollerar de returnerade raderna rapporterar "sparat" när inget sparades. Läs tillbaka dina skrivningar efter att du aktiverat RLS, eller be om ett antal med `Prefer: count=exact`.

Före RLS, med samma grants, kunde den publika nyckeln läsa alla 3 rader, infoga, och uppdatera eller ta bort vilken rad som helst. Användare A kunde ändra och ta bort användare B:s rad och lämna över sina egna rader till B.

## Hur gör du tabellen användbar igen?

Skriv en policy per operation. Den vanliga uppsättningen för egna 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 dem såg användare A sina 2 rader och användare B sin 1. Den publika nyckeln såg fortfarande 0. När A försökte infoga en rad som ägs av B, eller flytta sin egen rad till B, blev svaret `403, 42501`. Det nekandet kommer från `with check` på update. När A försökte uppdatera eller ta bort B:s rad blev svaret `200, 0 rader`. Fler mönster (publika profiler, team, MFA) finns i [Supabase RLS policy-exempel, testade via API:t](https://madsalt.tech/sv/blog/supabase-rls-policy-examples/).

En detalj från den hemliga nyckeln: en rad den infogade fick `user_id = null`, eftersom `auth.uid()` inte har någon användare bakom den nyckeln. RLS hoppades över, men standardvärdet gjorde inte det som kolumnnamnet antyder.

## Vad läste den publika nyckeln efter varje steg?

![Rader den publika nyckeln läste, av 3. En Supabase-tabell med 3 rader, efter varje steg. Ny tabell, inget grant, RLS av (fel 42501): 0; Grant tillagt, RLS av: 3; RLS på, ingen policy: 0; RLS på, policyer för egna rader: 0; Vanlig vy över tabellen: 3; Vy med security_invoker: 0.](https://madsalt.tech/charts/sv/how-to-enable-rls-in-supabase.svg)

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

Två steg läcker allt: ett grant utan RLS och en vanlig vy över en tabell med korrekta policyer. De följande två avsnitten förklarar båda.

## Behöver du fortfarande RLS efter grant-ändringen den 30 oktober?

Ja. Sedan den 30 oktober 2026 ger Supabase inte längre nya tabeller i `public` automatiska grants till API-rollerna, varken på nya eller befintliga projekt. Min lokala stack beter sig redan så. En nyskapad tabell med RLS av svarade `42501` till varje roll, även den hemliga nyckeln, så inget läckte. Detaljerna finns i [Supabase 30 oktober: vad som går sönder och hur du kollar](https://madsalt.tech/sv/blog/supabase-october-30-grant-change/).

Men granten kommer tillbaka så fort appen behöver tabellen, och från då är RLS det enda som står mellan den publika nyckeln och varje rad. Så lägg allt i en migrering, i den här ordningen:

```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;
```

Ge grants bara till de roller som behöver tabellen. När jag drog in allt från `anon` ändrades den publika nyckelns select från `200 []` till `401, 42501`. Granten är det första låset, RLS det andra.

## Varför läcker en vy ändå rader?

Därför att en vy körs med sin ägares rättigheter, och i Supabase är det `postgres`, som kringgår RLS. Med policyerna för egna rader på plats på `todos` gav en vanlig `create view public.todos_view as select * from public.todos` alla 3 rader till den publika nyckeln och till användare B.

Skapad på nytt `with (security_invoker = true)` gav samma vy 0 rader till den publika nyckeln, 2 till A och 1 till B, precis som tabellen:

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

Supabases Advisor flaggar den vanliga sorten som `security_definer_view`; vad det betyder och hur du åtgärdar det finns i [noten om Supabase security definer view](https://madsalt.tech/sv/notes/supabase-security-definer-view/).

## Hur aktiverar du RLS på varje ny tabell automatiskt?

Med en event trigger. Supabases [guide till event triggers](https://supabase.com/docs/guides/database/postgres/event-triggers) ger en funktion `rls_auto_enable()` och en trigger `ensure_rls` som körs efter `create table`, `create table as` och `select into` i `public`. Jag installerade den som den är publicerad och fick:

- En tabell som skapades efteråt med `create table` hade RLS på utan någon `alter`. Den publika nyckeln fick `200 []` på select och `401` på insert.
- En tabell som skapades med `create table as select` hade också RLS på.
- En tabell som skapades före triggern förblev av. Triggern gäller inte retroaktivt.

Utan triggern hade en andra tabell, skapad bredvid den skyddade, RLS av, och när den väl fått ett grant kunde den publika nyckeln läsa och skriva den fritt. Den täcker dessutom bara `public`; andra exponerade scheman behöver sin egen rad i funktionen.

## Hjälper FORCE ROW LEVEL SECURITY?

Inte för de roller du oroar dig för. `alter table ... force row level security` får RLS att gälla även tabellens ägare. I Supabase har både `postgres` och `service_role` `BYPASSRLS`, så efter `force` räknade ägaren fortfarande 3 rader, den hemliga nyckeln såg fortfarande allt, och en vy som ägs av `postgres` läckte fortfarande. Det ändrade bara något för en ägarroll jag skapade utan `BYPASSRLS`: 2 rader före, 0 efter.

## Hur kontrollerar du ditt eget projekt?

- Lista i SQL-editorn tabellerna 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 dashboarden rapporterar samma sak som `rls_disabled_in_public`; vad det felet betyder finns i [noten om RLS disabled in public](https://madsalt.tech/sv/notes/supabase-rls-disabled-in-public/).
- Den kostnadsfria [Supabase security check](https://madsalt.tech/sv/tools/supabase-security-check/) läser ditt projekt skrivskyddat och listar tabeller med RLS av som API:t kan nå, vyer som kringgår RLS och policyer som släpper in alla, med åtgärds-SQL för var och en.
- En skanner kan inte veta vilka rader som tillhör vem. För att bevisa det, skicka förfrågningar som två användare, som ovan. Hela metoden för en app med roller finns i [Testa Supabase RLS: 30 av 87 behörigheter gjorde inget](https://madsalt.tech/sv/blog/how-to-test-supabase-rls/).

## Så testade jag

- Supabase CLI 2.109.1 på en bärbar dator: Postgres 17.6, PostgREST 14.14, Auth 2.192.0. Två användare inloggade med lösenord, plus de lokala publishable och secret keys.
- En tabell, `public.todos`, återställd till samma 3 rader före varje förfrågan. Varje steg utfördes som SQL, och varje förfrågan gick över REST-API:t, med statuskod och body antecknade.
- Grants för steg 2 till 5 lades till för hand, för att motsvara ett projekt som skapats före den 30 oktober 2026.

**Begränsningar.** En lokal stack, påhittad data, 28 oktober 2026. Dashboard-stegen är citerade från Supabases dokumentation, inte klickade igenom. Tabeller som skapas av dashboardens egen roll kan få andra standardgrants. Det testade jag inte, inte heller Storage, Realtime eller GraphQL.

Osäker på om dina tabeller är låsta?

Jag tittar gärna på ett schema tillsammans med dig. Ingen säljpitch.

[Kontakta mig](https://madsalt.tech/sv/#contact)
