Hopp til innhold

Supabase 30. oktober: hva som knekker og hvordan sjekke

Vis som MarkdownÅpne i ClaudeÅpne i ChatGPTÅpne i Perplexity

Spørsmålet kopieres også. Hvis chatten åpnes tom, lim det inn.

TL;DR

  1. 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 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 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:

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.
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.
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 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.

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 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å:

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:

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:

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:

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.

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 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.

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 deg gjennom det, og notatet om eksponerte skjemaer dekker andre skjemaer enn public, som denne endringen lar stå i fred.

© 2026 Denys Zaichenko. Opprinnelig artikkel: https://madsalt.tech/no/blog/supabase-october-30-grant-change/