Apprends à gérer la session utilisateur sécurisée via cookies en React Router 7. Protège tes routes et personnalise l’expérience utilisateur facilement.
avec React Router 7
Posez vos questions 24/7 à notre IA experte en React Router 7
Validez vos acquis avec des quiz personnalisés et un feedback instantané
Dans un navigateur tu disposes de plusieurs espaces de stockage :
– localStorage
, sessionStorage
, IndexedDB
côté client
– les cookies qui voyagent dans chaque requête HTTP.
localStorage
est pratique pour retenir un thème ou la vitesse d’un player
YouTube, mais il est :
Pour authentifier un utilisateur nous avons besoin de l’inverse :
une valeur qu’on ne peut pas lire côté client (httpOnly) et qui
accompagne chaque requête pour identifier la session.
C’est exactement ce que proposent les cookies.
createCookieSessionStorage
React Router 7 expose une API qui masque toute la plomberie de parsing/sérialisation :
1import { createCookieSessionStorage } from "react-router"23type SessionData = {4userId: string5theme: "light" | "dark"6lang: "en" | "fr"7}89export const { getSession, commitSession, destroySession }10= createCookieSessionStorage<SessionData>({11cookie: {12name: "__session",13// secrets en production !14// secrets: [process.env.SESSION_SECRET!],15sameSite: "lax",16httpOnly: true,17path: "/",18// secure: process.env.NODE_ENV === "production",19}20})
Trois helpers sortent :
Helper | Rôle |
---|---|
getSession | Lire + décoder le cookie reçu |
commitSession | Encoder + renvoyer Set-Cookie |
destroySession | Supprimer le cookie (déconnexion) |
1import { Form, redirect, type ActionFunctionArgs } from "react-router"2import { commitSession, getSession } from "~/server/sessions.server"34export async function action({ request }: ActionFunctionArgs) {5// 1. on récupère la session courante (peut être vide)6const session = await getSession(request.headers.get("Cookie"))78// 2. … ici tu valides email + mot de passe contre la DB …9// on triche : user #1 est toujours correct10session.set("userId", "1")1112// 3. tu peux aussi stocker des préférences13session.set("theme", "dark")14session.set("lang", "fr")1516// 4. on renvoie une redirection + Set-Cookie17return redirect("/dashboard", {18headers: {19"Set-Cookie": await commitSession(session),20},21})22}
Le cookie est crypté par la / les clé(s)
secrets
: impossible de deviner l’userId
depuis le navigateur.
loader
1import { data, type LoaderFunctionArgs, redirect }2from "react-router"3import { getSession } from "~/server/sessions.server"45export async function loader({ request }: LoaderFunctionArgs) {6const session = await getSession(request.headers.get("Cookie"))7const userId = session.get("userId")89if (!userId) {10// non authentifié → on renvoie vers /login11throw redirect("/login")12}1314// tu peux récupérer la préférence utilisateur15const theme = session.get("theme") // "dark" | "light"16return data({ userId, theme })17}
Ici on protège la route : sans cookie → pas d’accès.
1import { useLoaderData, Form, type ActionFunctionArgs } from "react-router"2import { commitSession, getSession } from "~/server/sessions.server"34export async function action({ request }: ActionFunctionArgs) {5const session = await getSession(request.headers.get("Cookie"))6const form = await request.formData()7const theme = form.get("theme") // "light" | "dark"89session.set("theme", theme)10return redirect("/settings", {11headers: { "Set-Cookie": await commitSession(session) }12})13}
React Router renvoie automatiquement le cookie mis à jour, le navigateur
l’enregistrera et tu pourras le relire au prochain loader
.
destroySession
1import { redirect, type ActionFunctionArgs } from "react-router"2import { destroySession, getSession } from "~/server/sessions.server"34export async function action({ request }: ActionFunctionArgs) {5const session = await getSession(request.headers.get("Cookie"))6return redirect("/login", {7headers: {8"Set-Cookie": await destroySession(session),9},10})11}
Le cookie est supprimé ; les loader
protégés renverront
immédiatement vers /login
.
requireUserId
Pour ne pas répéter le « si pas de cookie ⇒ redirect » dans chaque route, crée un helper :
1import { redirect } from "react-router"2import { getSession } from "~/server/sessions.server"34export async function requireUserId(request: Request) {5const session = await getSession(request.headers.get("Cookie"))6const id = session.get("userId")7if (!id) throw redirect("/login")8return id9}
Puis utilise-le dans chaque loader
sensible.
1export async function loader({ request }) {2const userId = await requireUserId(request) // focus sur la logique métier3/* … */4}
__session
) transporte toutes les infos
liées à l’utilisateur.createCookieSessionStorage
te donne :getSession
→ lire ; commitSession
→ écrire ; destroySession
→ delete.secrets
et à httpOnly
, le cookie n’est
jamais accessible par window.document.cookie
→ protection XSS.requireUserId()
centralise la logique de garde.Durée de vie limitée
Ajoute maxAge: 60
dans la config du cookie puis observe qu’au bout de
60 s un refresh de /dashboard
te renvoie sur /login
.
Préférence de langue
– Stocke lang
dans la session lors du login.
– Ajoute un sélecteur dans /settings
pour passer de fr à en
(pense à commitSession
).
– Utilise lang
dans le loader
de /
pour afficher
« Bonjour » ou « Hello ».
Page protégée globale
Crée utils/withAuth.ts
qui enveloppe n’importe quel loader
:
1export const withAuth = (loader: LoaderFunction) =>2async (args: LoaderFunctionArgs) => {3await requireUserId(args.request)4return loader(args)5}
Refactorise deux routes pour tester le HOC.
Happy hacking !
Quelle est la principale différence entre les composants client et serveur dans React ?
Quelle technique est recommandée pour éviter les rendus inutiles dans React ?
Quel hook permet de gérer les effets de bord dans un composant React ?
Comment implémenter la gestion des erreurs pour les requêtes API dans React ?
Quelle est la meilleure pratique pour déployer une application React en production ?