Apprends à gérer la session utilisateur avec React Router 7 en récupérant l’id depuis les cookies pour sécuriser et personnaliser tes routes 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é
Une fois ton formulaire de connexion validé, React Router 7 place l’id de l’utilisateur dans un cookie de session.
Notre objectif dans cette leçon : retrouver cet id à chaque requête, charger l’utilisateur en base et exposer ces infos, côté serveur comme côté client, via un helper ultra-simple : getOptionalUser()
.
React Router fournit la factory createCookieSessionStorage()
(alias CSSS) qui lit, signe et détruit tes cookies pour toi.
Crée un fichier dédié :
1import { createCookieSessionStorage } from "react-router"23type SessionData = { userId: string }4type SessionFlashData = { error: string }56const { getSession, commitSession, destroySession } =7createCookieSessionStorage<SessionData, SessionFlashData>({8cookie: {9name: "__session",10sameSite: "lax",11httpOnly: true,12path: "/",13secrets: [process.env.SESSION_SECRET!], // 🔐14secure: process.env.NODE_ENV === "production",15},16})1718export { getSession, commitSession, destroySession }
Ici on ne stocke qu’une seule clé (userId
).
Si tu as aussi un thème ou une langue, crée d’autres cookies – mêler tout
dans la même session complique la vie (lecture sur chaque route, invalidation, etc.).
Dans l’action
de ta route /login
tu reçois l’utilisateur (ex. via Prisma),
puis tu places son id
dans la session :
1import { commitSession, getSession } from "~/server/sessions.server"23export async function action({ request }: ActionFunctionArgs) {4const form = await request.formData()5const user = await prisma.user.findUnique({6where: { email: form.get("email") as string },7})8/* … vérification mot de passe … */910const session = await getSession(request.headers.get("Cookie"))11session.set("userId", String(user.id))1213return redirect("/", {14headers: { "Set-Cookie": await commitSession(session) },15})16}
Le cookie signé est envoyé dans le header Set-Cookie
.
À la requête suivante, il arrivera automatiquement dans request.headers.get("Cookie")
.
Plutôt que de copier/coller getSession
partout, ajoutons
deux helpers :
1// …23export async function getUserId({ request }: { request: Request }) {4const session = await getSession(request.headers.get("Cookie"))5return session.get("userId") as string | undefined6}78export async function getOptionalUser({ request }: { request: Request }) {9const userId = await getUserId({ request })10if (!userId) return null1112// ⚠️ le cookie peut être forgé : on vérifie qu’il existe vraiment13return prisma.user.findUnique({14where: { id: Number(userId) },15select: { id: true, firstName: true, lastName: true },16})17}
Pourquoi « optional » ?
La fonction peut renvoyer null
: un visiteur anonyme n’est pas une erreur.
a. Empêcher un utilisateur connecté d’accéder à /login
:
1import { getOptionalUser } from "~/server/sessions.server"23export async function loader({ request }: LoaderFunctionArgs) {4const user = await getOptionalUser({ request })5if (user) return redirect("/") // déjà loggé → retour home6return null7}
b. Afficher l’utilisateur dans le loader de la racine :
1export async function loader({ request }: LoaderFunctionArgs) {2const user = await getOptionalUser({ request })3return data({ user })4}
Côté client :
1const { user } = useLoaderData<typeof loader>()23<header>4{/* … */}5{user ? (6<Form method="POST" action={href("/logout")}>7<button type="submit">Logout</button>8</Form>9) : (10<Link to={href("/login")}>Login</Link>11)}12</header>
/logout
Un simple POST détruit la session puis redirige :
1import { destroySession, getSession } from "~/server/sessions.server"23export async function action({ request }: ActionFunctionArgs) {4const session = await getSession(request.headers.get("Cookie"))5return redirect("/", {6headers: { "Set-Cookie": await destroySession(session) },7})8}
Les loaders utilisent une ligne pour récupérer l’utilisateur, les actions n’ont plus qu’à écrire :
1const id = await getUserId({ request })2if (!id) throw redirect("/login")
Lisibilité + sécurité = ❤️
createCookieSessionStorage()
gère la lecture/écriture/suppression du cookie.getUserId()
puis getOptionalUser()
suppriment la duplication
et vérifient que le cookie pointe vers un vrai user./logout
détruit la session.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 ?