Vlastní getUser() v API route závodí s refreshem session v middleware
import { Aside } from ‘@astrojs/starlight/components’;
Symptom
Sekce “Symptom”Na dlouho otevřené (admin) stránce občas akce přes fetch (odeslat zprávu, uložit) spadne na červené „Authentication required”, i když je uživatel přihlášený. Po reloadu stránky to chvíli funguje, pak zas ne. Opakující se, těžko reprodukovatelné.
Root cause
Sekce “Root cause”Middleware správně obnovuje session a plní locals.user:
let { data: { user } } = await supabase.auth.getUser();if (!user && refreshTokenCookie) { const { data } = await supabase.auth.refreshSession(); // zapíše nové cookies, nastaví locals.user}Ale API endpoint si dělal vlastní ověření:
// ŠPATNĚ — druhá, nezávislá validaceconst { data: { user }, error } = await supabase.auth.getUser();if (error || !user) return 401;getUser() re-validuje access token. Když vypršel (JWT ~1 h), pokusí se o refresh — ale refresh tokeny rotují (jsou single-use). Middleware už refresh provedl a token spotřeboval; endpointova druhá validace pak selže → 401. Na čerstvě načtené stránce token platí, takže to „někdy funguje”.
Fix
Sekce “Fix”Endpoint čte uživatele z locals (vyřešeno middlewarem), ne vlastním getUser:
export const POST = async ({ request, locals }) => { const user = locals.user; // vyřešeno + refreshnuto middlewarem if (!user) return 401; const role = locals.profile?.role; // taktéž z middleware // ...};Jak se tomu vyvarovat v jiných systémech
Sekce “Jak se tomu vyvarovat v jiných systémech”- Detection: grep
getUser()/getSession()v API endpointech. Pokud middleware už řeší session, je to duplicitní + race-prone. - Anti-pattern: dvě nezávislá místa validující/refreshující stejný token; re-validace tokenu na write cestě.
- Lepší přístup: (1) jeden zdroj pravdy pro auth (middleware → locals/context); (2) refresh tokeny rotují → nikdy je nevaliduj paralelně dvakrát; (3) test: nech stránku „vyčkat” přes expiraci access tokenu a spusť fetch akci.