Implémente la gestion de session, cookies httpOnly et redirections.
Renseigne ton email pour débloquer immédiatement cette formation gratuite.
Bienvenue dans cette leçon dédiée à la persistance de l’authentification grâce aux cookies sécurisés sous Next.js 15. Tu vas découvrir comment :
La session en cookie permet de :
Ces bonnes pratiques réduisent les risques de vol de session et d’attaque XSS.
Next.js 15 expose un helper cookies()
utilisable exclusivement dans un contexte serveur ('use server'
).
Tu peux :
1'use server'2import { cookies } from 'next/headers'3import { prisma } from './db'45const sessionCookieName = 'user_session'67export async function setUserId({ userId }: { userId: string }) {8const cookieStore = await cookies()9cookieStore.set(sessionCookieName, userId, {10secure: process.env.NODE_ENV === 'production', // @callout: actif en prod seulement11httpOnly: true, // @callout: interdit l’accès en JS12path: '/', // ^? accessible sur tout le domaine13maxAge: 60 * 60 * 24 * 30, // ^? durée de vie : 30 jours14})15}1617export async function getUserId() {18const cookieStore = await cookies()19return cookieStore.get(sessionCookieName)?.value ?? null20}2122export async function logout() {23const cookieStore = await cookies()24cookieStore.delete(sessionCookieName)25}2627export async function getOptionalUser() {28const userId = await getUserId()29if (!userId) return null30return prisma.user.findUnique({31where: { id: Number(userId) },32select: { email: true },33})34}3536export async function requireUser() {37const user = await getOptionalUser()38if (!user) throw new Error('Utilisateur non authentifié')39return user40}
httpOnly
empêche tout script d’y accéder, et secure
ne lèvera le cookie qu’en HTTPS.
Dans ton server/auth.ts, après avoir validé l’utilisateur, il suffit d’appeler setUserId
pour déclencher la création du cookie, puis redirect('/')
pour renvoyer la home page.
1'use server'2import { redirect } from 'next/navigation'3import { setUserId } from './session'4import { compare } from 'bcryptjs'5import { prisma } from './db'67export async function login(8prevState: unknown,9formData: FormData10) {11'use server'12const email = formData.get('email') as string13const password = formData.get('password') as string1415const user = await prisma.user.findUnique({ where: { email } })16if (!user) throw new Error('Utilisateur non trouvé')1718const valid = await compare(password, user.password)19if (!valid) throw new Error('Mot de passe invalide')2021await setUserId({ userId: user.id.toString() })22redirect('/')23}
Pour sécuriser l’accès à /history
, utilise requireUser()
en début de ta Server Component :
1'use server'2import { requireUser } from '../server/session'3import { HistoryList } from './HistoryList'4import { getHistory } from '../server/history'56export default async function HistoryPage() {7const user = await requireUser()8const items = await getHistory()9return <HistoryList user={user} initialHistoryItems={items} />10}
requireUser()
lève une exception si l’utilisateur n’est pas connecté : pense à gérer le catch pour rediriger.
Dans app/layout.tsx
, fais appel à getOptionalUser()
pour afficher l’email et un formulaire Logout
.
Le form action peut être une lambda 'use server'
qui appelle logout()
.
1...2export default async function RootLayout({ children }: { children: ReactNode }) {3const user = await getOptionalUser()4return (5<html lang="fr">6<body>7<nav>8{user ? (9<>10<span>{user.email}</span>11<form action={async () => {12'use server'13await logout()14}}>15<button type="submit">Logout</button>16</form>17</>18) : (19<>20<Link href="/login">Login</Link>21<Link href="/register">Register</Link>22</>23)}24</nav>25{children}26</body>27</html>28)29}
En mode développement, ton cookie n’est pas chiffré. Sois sûr d’avoir secure: true
en production.
httpOnly
+ secure
renforcent la sécurité.path: '/'
et maxAge
approprié.getOptionalUser()
pour récupérer le user ou null.requireUser()
pour forcer l’accès authentifié.Configurer un cookie
Dans app/server/session.ts
, modifie maxAge
pour 7 jours au lieu de 30 et teste la suppression automatique.
Protéger une API route
Crée app/api/profile/route.ts
qui retourne les infos de l’utilisateur connecté ou 401 si non authentifié (utilise requireUser()
).
Test de logout
Ajoute un message flash après déconnection :
flash="À bientôt !"
Bonne session !