Il sintomo che ti fa impazzire
L'utente fa login. Vede la dashboard per mezzo secondo. Poi viene rispedito al login. Senza errori in console. Senza messaggi nei log. Solo un loop.
In localhost:3000 tutto funziona. In produzione, no.
Cos'è davvero un cookie
Un cookie è una stringa che il server appiccica al browser dopo il login, e che il browser rispedisce al server ad ogni richiesta successiva. È il braccialetto che ti danno all'ingresso del concerto: non devi rifare la fila ogni volta che vai al bar.
Quando il login funziona, il server risponde con un header Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax. Quel cookie viene salvato dal browser e rinviato automaticamente nelle richieste successive.
Le 4 flag che cambiano tutto
HttpOnly
Il cookie non è leggibile da JavaScript. È l'unico modo serio per evitare che un XSS rubi la sessione. Sempre attiva su cookie di sessione.
Secure
Il cookie viene inviato solo su HTTPS. In localhost (HTTP) è OK disattivata. In produzione è obbligatoria. Se per errore c'è un redirect HTTP, il cookie sparisce e il login si rompe.
SameSite
Controlla se il cookie viene inviato in richieste cross-site. Le opzioni:
Strict: solo richieste dal tuo stesso dominio.Lax: anche da link esterni che portano al tuo sito (default sensato).None: ovunque (richiedeSecure). Necessario solo se il tuo frontend è su un dominio diverso dal backend.
Domain & Path
Se il cookie è settato su miosito.com, è valido anche su app.miosito.com. Se è settato su app.miosito.com, NON è valido su api.miosito.com. Errore classico: setti il cookie sul subdominio sbagliato.
Sessions vs JWT — cosa scegliere
Sessions classiche: il cookie contiene solo un ID. Il vero stato (chi è l'utente, quando ha fatto login) è in un DB/Redis lato server. Pro: revoca immediata. Contro: richiede storage server-side.
JWT: il cookie contiene il token firmato con tutti i dati. Pro: nessuno storage server. Contro: revoca difficile (devi mantenere una blocklist).
Per la maggior parte delle app vibecoded, NextAuth/Supabase Auth con sessions è la scelta sensata. JWT solo se sai di averne bisogno.
I 5 motivi per cui il login si rompe in produzione
- Cookie
Securema sito su HTTP per via di un redirect mancante. Fix: forza HTTPS in nginx, sempre. - Domain del cookie sbagliato. Fix: configura
cookieDomainesplicitamente in NextAuth. - SameSite=Strict + login da link esterno. Fix: usa
Lax. - NEXTAUTH_SECRET diverso tra build e runtime. Fix: imposta la stessa env var su tutti gli ambienti (vedi i 5 motivi del deploy che si rompe).
- Backend e frontend su domini diversi senza configurare
credentials: 'include'e CORS conAccess-Control-Allow-Credentials: true.
📘 Tutto il modulo Auth nel libro
Nel libro Vibecoding Serio il Modulo 7 è dedicato a cookie, sessioni, JWT, OAuth e CORS — con un'infografica della "vita di un cookie httpOnly su HTTPS" e prompt-ready per fixare i 5 problemi più comuni.
Compra il libro — €14,90→Come parlarne a Claude
Sintomo: l'utente fa login (200 OK su /api/auth/callback/credentials), viene reindirizzato a /dashboard, ma /dashboard rimanda a /login. Loop infinito.
In localhost:3000 funziona. Nel network tab vedo che il cookie next-auth.session-token NON viene inviato sulla seconda richiesta.
Mostra come configurare cookies.sessionToken.options in authOptions per produzione: Secure=true, SameSite=Lax, domain corretto.