Autentificare și sesiuni
Sesiuni în DB vs JWT, unde ții tokenul, DAL și librării de auth.
Actualizat
Ce sunt autentificarea, autorizarea și sesiunea
Trei concepte diferite, des amestecate:
| Concept | Întrebarea | Exemplu |
|---|---|---|
| Autentificare | Cine ești? | login cu email + parolă, Google, magic link |
| Sesiune | Cum te recunosc la request-ul următor? | un cookie trimis automat la fiecare request |
| Autorizare | Ai voie să faci asta? | doar autorul își poate șterge postarea |
Cum funcționează împreună: te autentifici o dată → serverul creează o sesiune și îți pune un cookie → la fiecare request, serverul citește cookie-ul, află cine ești și verifică dacă ai voie (autorizare).
Două tipuri de sesiuni
Sesiune în baza de date (stateful)
Cookie-ul conține doar un id aleator. Datele sesiunii (userul, expirarea) stau pe server, într-o tabelă sessions sau în Redis.
Sesiune în cookie (stateless, JWT)
Cookie-ul conține datele însele (userId, expirare), semnate (sau criptate) cu o cheie secretă de pe server. Serverul verifică semnătura — fără să interogheze baza de date. Formatul folosit des: JWT.
| Database session | Stateless (JWT în cookie) | |
|---|---|---|
| Ce e în cookie | id aleator | datele, semnate |
| Interogare DB la fiecare request | da (sau cache) | nu |
| Logout / revocare instantă | da — ștergi rândul | greu — tokenul e valid până expiră |
| „Deconectează toate dispozitivele” | ușor | greu |
| Mărime cookie | mică | mai mare |
| Când | aplicații cu date sensibile, control fin | aplicații simple, multe servere fără DB comun |
Unde ții tokenul — regula importantă
| Loc | Verdict |
|---|---|
cookie HttpOnly; Secure; SameSite=Lax |
✓ corect — JS nu-l poate citi, deci nici un script injectat (XSS) |
localStorage / sessionStorage |
✗ orice script de pe pagină îl poate fura |
| variabilă în memorie (SPA) | posibil, dar se pierde la reload; necesită refresh token în cookie |
Access token și refresh token
Pentru API-uri, des se folosesc două tokenuri:
| Access token | Refresh token | |
|---|---|---|
| Durată | scurtă (minute) | lungă (zile, săptămâni) |
| Folosit la | fiecare request | doar ca să obții un access token nou |
| Dacă e furat | pagubă limitată în timp | poate fi revocat pe server |
Sesiuni în Next.js — piesele
// shared/api/session.ts
import 'server-only'
import { SignJWT, jwtVerify } from 'jose'
import { cookies } from 'next/headers'
const key = new TextEncoder().encode(process.env.SESSION_SECRET)
export async function createSession(userId: string) {
const expires = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
const token = await new SignJWT({ userId }).setProtectedHeader({ alg: 'HS256' }).setExpirationTime(expires).sign(key)
;(await cookies()).set('session', token, { httpOnly: true, secure: true, sameSite: 'lax', expires, path: '/' })
}
export async function readSession() {
const token = (await cookies()).get('session')?.value
if (!token) return null
try {
return (await jwtVerify(token, key, { algorithms: ['HS256'] })).payload as { userId: string }
} catch {
return null
}
}Unde verifici — straturile
| Strat | Rol | Suficient singur? |
|---|---|---|
proxy.ts |
verificare optimistă: „are cookie?” → redirect la /login |
nu — doar UX, rapid |
Data Access Layer (verifySession) |
verifică sesiunea real, o dată per request (cache()) |
da — aici e securitatea |
| fiecare Server Action / Route Handler | autentificare + autorizare pe resursa concretă | obligatoriu |
| UI (ascunzi butoane) | doar experiență | niciodată |
// shared/api/dal.ts
import 'server-only'
import { cache } from 'react'
import { redirect } from 'next/navigation'
export const verifySession = cache(async () => {
const session = await readSession()
if (!session) redirect('/login')
return session
})Layout-urile nu re-verifică la fiecare navigare (sunt păstrate). Pune verificarea în pagină, în DAL sau în acțiune — nu doar în layout.
Librării — nu-ți scrie singur autentificarea
| Librărie | Tip | Când |
|---|---|---|
| Auth.js (NextAuth) | open-source, în aplicația ta | OAuth (Google, GitHub), sesiuni în DB sau JWT |
| Better Auth | open-source, în aplicația ta | email/parolă, OAuth, 2FA, organizații — complet și tipat |
| Clerk, Auth0, WorkOS, Stack Auth | serviciu găzduit | UI gata făcut, enterprise (SSO), fără întreținere |
| iron-session, jose | doar sesiuni | ai deja logica de login, îți trebuie doar cookie-ul |
Autentificarea are multe detalii de securitate (hash-uri de parolă, rate limiting, resetare parolă, CSRF). O librărie matură e aproape mereu alegerea corectă.
Pe scurt
- Autentificare = cine ești; sesiune = cum te recunosc; autorizare = ce ai voie.
- Sesiune în DB = revocare ușoară; JWT în cookie = fără interogare, revocare grea.
- Tokenul stă în cookie
HttpOnly; verifici în DAL și în fiecare acțiune, proxy-ul e doar optimist.