---
title: "Supabase 30. oktober: hva som knekker og hvordan sjekke"
description: "Fra 30. oktober 2026 gir Supabase nye public-tabeller ikke API-tilgang i eksisterende prosjekter. Hva som knekker, hva som virker, 4 sjekker, testet lokalt."
url: "https://madsalt.tech/no/blog/supabase-october-30-grant-change/"
author: "Denys Zaichenko"
language: "no"
published: 2026-10-26
---

# Supabase 30. oktober: hva som knekker og hvordan sjekke

TL;DR

30. oktober 2026 slutter Supabase å gi nye tabeller i `public` automatisk tilgang for `anon`, `authenticated` og `service_role` i alle eksisterende prosjekter. Tabeller du allerede har, fortsetter å virke. Hver tabell opprettet etter det svarer `42501 permission denied` til `supabase-js` og til secret key, helt til en migrasjon gir tilgang. Jeg reproduserte omleggingen lokalt: nye tabeller, nye views og gamle tabeller som en migrasjon dropper og lager på nytt feiler alle; eksisterende tabeller, RPC-funksjoner og `serial`-inserts fortsetter å virke. Sjekk med to SQL-spørringer og én grep under, og fiks med grant, RLS og policy i samme migrasjon, aldri med `grant all on all tables`.

Jeg driver en gratis [Supabase-sikkerhetssjekk](https://madsalt.tech/no/tools/supabase-security-check/) som leser tilgangene på hver eksponerte tabell, så jeg ville se nøyaktig hva denne endringen gjør før folk begynner å støte på den. Jeg tok en lokal Supabase-stack, ga den de gamle standardene, la inn omleggingen slik Supabase beskriver den, og sendte en forespørsel mot hver type objekt jeg kunne komme på. Dette innlegget er det som kom tilbake, og hvordan du sjekker ditt eget prosjekt før den 30.

## Hva endres 30. oktober 2026?

Til nå fikk hver tabell opprettet i `public`-skjemaet `select`, `insert`, `update` og `delete` for `anon`, `authenticated` og `service_role` gjennom Postgres default privileges. Derfor var en ny tabell tilgjengelig fra nettleseren i det øyeblikket den fantes, beskyttet av RLS eller ikke. Supabase sitt [varsel om brytende endring](https://supabase.com/changelog/45329-breaking-change-tables-not-exposed-to-data-and-graphql-api-automatically) fjerner disse standardene i tre steg:

| Dato             | Hva skjer                                                                       |
| ---------------- | ------------------------------------------------------------------------------- |
| 28. april 2026   | Nye prosjekter kan velge bort «Automatically expose new tables» ved opprettelse |
| 30. mai 2026     | Den nye oppførselen blir standard for nye prosjekter, rullet ut over noen uker  |
| 30. oktober 2026 | Den nye oppførselen gjelder alle eksisterende prosjekter                        |

I prosjektet ditt er omleggingen to setninger, de samme Supabase oppgir for å melde seg på tidlig:

```sql
alter default privileges for role postgres in schema public
  revoke select, insert, update, delete on tables from anon, authenticated, service_role;

alter default privileges for role postgres in schema public
  revoke usage, select on sequences from anon, authenticated, service_role;
```

Default privileges gjelder bare objekter som lages senere. Tilganger som allerede finnes, røres ikke, og det er derfor dagens tabeller fortsetter å virke. Det som ifølge varselet ikke påvirkes: andre skjemaer (`auth`, `storage`, `realtime`, dine egne), apper som snakker med Postgres over direkte tilkobling (psql, en ORM, en server med connection string), og selve RLS. Endringen gjelder Data API-et: REST, GraphQL og alle klientbibliotekene oppå dem.

## Hva knekker, og hva fortsetter å virke?

Oppsettet mitt: Supabase CLI 2.109.1, Postgres 17.6, PostgREST 14.14, 26. oktober 2026. Jeg satte `auto_expose_new_tables = true` i `config.toml` for å få de gamle standardene, opprettet én tabell med to rader, RLS på og en lesepolicy, og kjørte så de to setningene over. Etter det opprettet jeg nye objekter og kalte hvert av dem med den lokale offentlige nøkkelen (`anon`) og secret key (`service_role`), én forespørsel hver.

![Hva som slutter å svare etter omleggingen 30. oktober. Lokal Supabase, objekter opprettet etter changelog-revoke, offentlig nøkkel hvis ikke annet er oppgitt. Ny tabell med RLS og en policy: create table → policy, ingen grant → 42501, HTTP 401; Samme tabell med secret key: create table → policy, ingen grant → 42501, HTTP 403; Ny view over en tabell som fortsatt virker: create view → 42501, HTTP 401, uten hint; Gammel tabell droppet og gjenopprettet av en migrasjon: drop + create table → tilgang borte → 42501, HTTP 401.](https://madsalt.tech/charts/no/supabase-october-30-grant-change.svg)

*Min reproduksjon på en lokal Supabase-stack (CLI 2.109.1, Postgres 17.6, PostgREST 14.14), 26. oktober 2026.*

![Hva som fortsetter å virke etter omleggingen 30. oktober. Samme lokale stack, samme revoke, offentlig nøkkel. Tabell opprettet før omleggingen: eksisterende tabell → tilgang beholdt → 2 rader, HTTP 200; Ny funksjon kalt over RPC: create function → execute via PUBLIC → HTTP 200; Ny serial-tabell, bare select og insert gitt: id serial → sekvens-UPDATE igjen → insert, HTTP 201.](https://madsalt.tech/charts/no/supabase-october-30-grant-change-works.svg)

*Min reproduksjon på en lokal Supabase-stack (CLI 2.109.1, Postgres 17.6, PostgREST 14.14), 26. oktober 2026.*

| Objekt, opprettet etter omleggingen hvis ikke annet er oppgitt   | Nøkkel | Resultat                                                           |
| ---------------------------------------------------------------- | ------ | ------------------------------------------------------------------ |
| Tabell opprettet før omleggingen                                 | public | HTTP 200, 2 rader                                                  |
| Ny tabell med RLS og en `to anon, authenticated`-policy          | public | HTTP 401, 42501, hint `GRANT SELECT ON public.new_orders TO anon;` |
| Den samme nye tabellen                                           | secret | HTTP 403, 42501, hint `… TO service_role;`                         |
| Ny view (`security_invoker`) over den gamle tabellen             | public | HTTP 401, 42501, `permission denied for view`, hint `null`         |
| Kopi laget med `create table … (like old_orders including all)`  | public | HTTP 401, 42501                                                    |
| Den gamle tabellen etter `drop table` og ny `create table`       | public | HTTP 401, 42501                                                    |
| Ny funksjon `public.ping()` over `/rest/v1/rpc`                  | public | HTTP 200                                                           |
| Ny tabell med `id serial`, bare `select, insert` gitt til `anon` | public | insert HTTP 201                                                    |

Fem ting i den tabellen er verdt å vite før omleggingen.

**«Eksisterende tabeller beholder tilgangene sine» gjelder bare så lenge tabellen eksisterer.** En migrasjon som dropper og lager en tabell på nytt, en `create table … (like …)`-kopi eller en gjenoppretting fra dump lager en ny tabell, og en ny tabell får ingenting. Policyen kom tilbake med `create policy`, tilgangene gjorde det ikke. Alt i pipelinen din som bygger tabeller på nytt i stedet for å endre dem, knekker ved første kjøring etter omleggingen.

**Secret key knekker også.** `service_role` hopper over RLS, men trenger fortsatt en tilgang. En Edge Function, en cron-jobb eller en webhook-handler som skriver til en ny tabell feiler altså med 403, ikke bare nettleseren. Hintet nevner `service_role`, og slik skiller du dem.

**Views gir deg ikke noe hint.** For tabeller returnerer PostgREST nøyaktig den `GRANT` du trenger. For min nye view var hintet `null`, og meldingen lød `permission denied for view v_old_orders`. Et AI-verktøy som fikser 42501 ut fra hintet har ingenting å kopiere her; tilgangen er `grant select on public.v_old_orders to authenticated;`, og viewen bør beholde `security_invoker = true` slik at RLS på tabellen fortsatt gjelder.

**Funksjoner er ikke en del av denne endringen.** De to setningene berører tabeller og sekvenser. Den nye funksjonen min forble kallbar for `anon`, `authenticated` og `service_role`, fordi Postgres gir `execute` på hver ny funksjon til `PUBLIC`, og en revoke på skjemanivå kan ikke fjerne det, som [Supabase sin guide for API-sikkerhet](https://supabase.com/docs/guides/api/securing-your-api) forklarer. RPC-kall fortsetter å virke etter 30. oktober; det betyr også at en ny `security definer`-funksjon er kallbar med den offentlige nøkkelen din i det øyeblikket den finnes.

**`serial`-inserts virket uten tilgang på sekvensen.** Mye råd sier at en `serial`-id trenger `grant usage on sequence … to authenticated` etter omleggingen. I kjøringen min gikk inserten gjennom uten: revoke tar `usage` og `select` på nye sekvenser, men `update` blir stående, og `update` er nok for `nextval`. Hvis du trekker tilbake alle default privileges på sekvenser, som den fulle revoke-en i guiden for API-sikkerhet gjør, trenger du `usage`-tilgangen. En identity-kolonne (`generated by default as identity`) trenger ingenting uansett.

Én ting til som revoke-en lar stå: den nye tabellen kom fortsatt med `TRUNCATE`, `REFERENCES` og `TRIGGER` for alle tre rollene, og på Postgres 17 inneholder standardene også `MAINTAIN`. Ingen RLS-policy gjelder for `TRUNCATE`. Det tok jeg for meg i [42501-notatet](https://madsalt.tech/no/notes/supabase-42501-permission-denied/).

## Hvor du møter det før 30. oktober

Omleggingen på det hostede prosjektet ditt skjer den 30., men tre steder oppfører seg allerede som etter den.

**`supabase db reset` på en nyere CLI.** CLI v2.102.0 la til `[api] auto_expose_new_tables` i `config.toml`. På 2.109.1, med nøkkelen utelatt, hadde den ferske stacken min allerede de nye standardene: tabeller fikk bare `MAINTAIN`, `REFERENCES`, `TRIGGER` og `TRUNCATE`, sekvenser bare `UPDATE`. Setter du den til `true`, kommer de gamle tilgangene tilbake og det skrives ut `api.auto_expose_new_tables is deprecated and will be removed on 2026-10-30`. Så hvis de lokale tabellene dine fortsatt virker etter en reset, sjekk den nøkkelen først. Det er også det billigste stedet å teste: fjern den, kjør reset, kjør appen.

**Preview-grener og prosjekter opprettet siden 30. mai.** De spiller av migrasjonene dine på de nye standardene. Hver tabell hvis migrasjon mangler `grant`, er allerede utilgjengelig der. I [GitHub-diskusjonen](https://github.com/orgs/supabase/discussions/45329) melder folk med ett prosjekt per kunde om akkurat dette: de kjørende prosjektene er fine, men hver ny utrulling fra de samme migrasjonene er ødelagt.

**En baseline-migrasjon som bringer den gamle standarden tilbake.** En kommentator i samme diskusjon peker på at en første migrasjon laget med `supabase db pull` kan inneholde `alter default privileges … grant all on tables to anon, authenticated, service_role`. Jeg kjørte den setningen etter omleggingen: neste tabell jeg opprettet, var tilgjengelig igjen, HTTP 200. Lokalt skjuler det problemet. Brukt på det hostede prosjektet ditt angrer den stille endringen, og hver fremtidige tabell er åpen for den offentlige nøkkelen igjen, enten den har RLS eller ikke. Søk i migrasjonene dine etter `alter default privileges` og les hver treff.

## Slik sjekker du prosjektet før 30. oktober

Fire sjekker, fra raskeste til mest grundige. De to første kjører i SQL Editor i det hostede prosjektet.

### 1. Er prosjektet ditt lagt om ennå?

Dette er spørringen fra Supabase sin guide for API-sikkerhet. Den lister hva nye objekter opprettet av `postgres` i `public` kommer til å få:

```sql
select
  case d.defaclobjtype
    when 'r' then 'tables'
    when 'S' then 'sequences'
    when 'f' then 'functions'
  end as object_type,
  a.grantee::regrole as role,
  string_agg(a.privilege_type, ', ' order by a.privilege_type) as privileges
from pg_default_acl d
cross join lateral aclexplode(d.defaclacl) a
where d.defaclrole = 'postgres'::regrole
  and d.defaclnamespace = 'public'::regnamespace
  and a.grantee in ('anon'::regrole, 'authenticated'::regrole, 'service_role'::regrole)
group by 1, 2
order by 1, 2;
```

Hvis `tables`-radene inneholder `SELECT, INSERT, UPDATE, DELETE`, er prosjektet fortsatt på den gamle standarden og legges om den 30. Viser de bare `MAINTAIN, REFERENCES, TRIGGER, TRUNCATE` (eller ingen rader), er nye tabeller allerede stengt. Du ser det også i Dashboard under Data API-innstillinger, «Automatically expose new tables».

### 2. Hvilke tabeller har en policy, men ingen tilgang?

En policy for en rolle som ikke har tilgang til den kommandoen, kjører aldri: forespørselen feiler før RLS. Denne spørringen lister slike par. I labben min fant den den nye tabellen og den gjenopprettede gamle, og ingenting annet:

```sql
select p.schemaname || '.' || p.tablename as "table", r.role, p.cmd
from pg_policies p
cross join lateral unnest(case when 'public' = any(p.roles) then array['anon', 'authenticated']::name[] else p.roles end) as r(role)
join pg_class c on c.relname = p.tablename
join pg_namespace n on n.oid = c.relnamespace and n.nspname = p.schemaname
where p.schemaname = 'public'
  and r.role in ('anon', 'authenticated')
  and not has_table_privilege(r.role::text, c.oid,
        case p.cmd when 'ALL' then 'SELECT' else p.cmd end)
order by 1, 2, 3;
```

Kjør den etter hver migrasjon, i CI mot en fersk `db reset` eller på staging. I et friskt prosjekt returnerer den ingenting; etter den 30. er hver rad en tabell appen din ikke når. Den sjekker tilganger på tabellnivå, så en tabell åpnet bare med kolonnetilganger (`grant select (id, name) on …`) dukker opp her selv om de kolonnene er lesbare.

### 3. Hvilke migrasjoner lager en tabell uten grant?

Databasen viser bare tabeller som finnes. En migrasjon du ikke har kjørt ennå, er bare synlig i repoet ditt. Denne grove grep-en lister hver `create table` i `supabase/migrations` uten `grant … on` for samme navn:

```bash
for t in $(grep -hioE 'create table( if not exists)? +[a-z0-9_."]+' supabase/migrations/*.sql | awk '{print $NF}' | sort -u); do
  grep -qiF "on $t " supabase/migrations/*.sql || grep -qiF "on table $t " supabase/migrations/*.sql || echo "no grant: $t"
done
```

Det er tekstmatching, ikke SQL-parsing: en grant som lister flere tabeller i én setning, eller en tabell som er navngitt uten skjema ett sted og med det et annet sted, gir falske treff. Les hver linje den skriver ut. Tabeller som bare serverkode når over direkte tilkobling, trenger ingen grant i det hele tatt.

### 4. Spill av alt på de nye standardene

Fjern `auto_expose_new_tables` fra `config.toml`, kjør `supabase db reset`, og kjør appen eller testene mot den. Det er prosjektet ditt etter den 30., pluss en fersk kopi av hver tabell, som er det vanskeligste tilfellet. Supabase lister også berørte tabeller i Security Advisor og markerer Data API-eksponering i Table Editor.

## Slik fikser du det uten å åpne hver tabell

Skriv grant, RLS og policyene i migrasjonen som lager tabellen, og gi hver rolle bare det appen bruker:

```sql
create table public.invoices (
  id bigint generated by default as identity primary key,
  user_id uuid not null default auth.uid(),
  total numeric not null
);

revoke all on table public.invoices from anon, authenticated, service_role;
grant select, insert on table public.invoices to authenticated;
grant select, insert, update, delete on table public.invoices to service_role;

alter table public.invoices enable row level security;

create policy "Owners read their invoices"
on public.invoices for select
to authenticated
using ((select auth.uid()) = user_id);

create policy "Owners add their invoices"
on public.invoices for insert
to authenticated
with check ((select auth.uid()) = user_id);
```

Jeg kjørte denne blokken på den samme lokale stacken: en innlogget testbruker satte inn en rad og leste den tilbake (HTTP 201, så 200), den offentlige nøkkelen uten sesjon fikk 42501, og sjekk 2 over listet ikke lenger tabellen. Den første `revoke all` rydder bort `TRUNCATE`, `TRIGGER` og `REFERENCES` som følger med en ny tabell, og gir samme resultat i et prosjekt som ikke er lagt om ennå. Gi `anon` tilgang bare på data som er ment for besøkende som ikke er innlogget, og `service_role` bare hvis serverkode bruker secret key på denne tabellen. Hvordan tilganger og policyer henger sammen i en hel app, står i [sikkerhetssjekklisten min for Lovable-apper](https://madsalt.tech/no/blog/lovable-app-security-checklist/).

Hva du ikke bør gjøre når den første 42501 kommer:

- **Ikke kjør `grant all on all tables in schema public to anon, authenticated`.** Den setter den gamle standarden tilbake for alle tabeller samtidig, også tabeller der RLS aldri ble slått på, og de blir lesbare for alle som har den offentlige nøkkelen din. [42501-notatet](https://madsalt.tech/no/notes/supabase-42501-permission-denied/) viser hvorfor tilgangen er den første låsen og RLS den andre.
- **Ikke legg til `alter default privileges … grant` igjen.** Det er tilbakerullingen av hele endringen.
- **Ikke slå av RLS for å «teste», og ikke legg secret key i frontend.** Secret key hopper over RLS for alle som åpner bundelen din; forskjellen mellom nøklene står i [anon key vs service role key](https://madsalt.tech/no/blog/supabase-anon-key-vs-service-role-key/).

Hvis et AI-verktøy skriver migrasjonene dine, legg til én linje i instruksjonene: «hver ny tabell i public får eksplisitte grants per rolle, slå på row level security og policyer i samme migrasjon; aldri grant på alle tabeller i schema public». Hintet i feilen lærer det grant, aldri RLS-en som hører sammen med den.

## Spørsmål folk stiller om endringen

**Slutter de eksisterende tabellene mine å virke 30. oktober?** Nei. Default privileges gjelder objekter som lages senere, og i mitt kjøring svarte den gamle tabellen HTTP 200 etter omleggingen. Unntaket er en tabell som migrasjonene dine dropper og lager på nytt.

**Må jeg gjøre noe hvis jeg aldri oppretter tabeller?** Ikke den 30. Sjekk neste gang du, en kollega eller et AI-verktøy legger til en, og sjekk hver pipeline som lager prosjekter eller grener fra migrasjonene dine.

**Påvirker det Edge Functions?** Ja, hvis de bruker `supabase-js` med secret key på en ny tabell: `service_role` trenger også en grant. Funksjoner som kobler til Postgres direkte, påvirkes ikke.

**Påvirker det RPC-funksjoner, Storage eller Auth?** Ikke i denne endringen. Nye funksjoner forblir kallbare via `PUBLIC`, og `storage` og `auth` er ikke `public`-skjemaet.

**Kan jeg legge om tidlig?** Ja. De to setningene øverst er omleggingen; kjør dem på staging først, så production. Eksisterende tabeller beholder tilgangene sine, så en kjørende app merker ingenting, og den neste nye tabellen forteller deg med en gang om migrasjonene dine er klare.

## Hvordan sjekken ser dette

Sjekken kobler til skrivebeskyttet og leser tilgangene på hver tabell i de eksponerte skjemaene dine: hvilke tabeller den offentlige nøkkelen kan skrive til uten policy, hvilke tabeller som har RLS av, og hvilke default privileges som fortsatt gir hver ny tabell `TRUNCATE`, `REFERENCES` eller `TRIGGER`. Den lister også hver policy der rollen mangler tilgang til den kommandoen, tabellene som sjekk 2 finner, unntatt de med RLS slått av eller med kolonne-grants. Den kan ikke se migrasjonsfiler du ikke har kjørt, så sjekk 3 over er din å kjøre. Hvis RLS er den delen du er usikker på, tar [hvordan teste Supabase RLS](https://madsalt.tech/no/blog/how-to-test-supabase-rls/) deg gjennom det, og [notatet om eksponerte skjemaer](https://madsalt.tech/no/notes/supabase-exposed-schemas/) dekker andre skjemaer enn `public`, som denne endringen lar stå i fred.
