JWT et cookies HttpOnly
Les jetons d'authentification sont déposés par le backend dans des cookies HttpOnly, illisibles par JavaScript. Le frontend ne les stocke plus dans localStorage : une faille XSS ne peut donc pas les voler.
Durées, routes et gestion des clés : voir Authentification JWT.
Cookies posés par le backend
| Cookie | Contenu | Chemin | Durée | Attributs |
|---|---|---|---|---|
BEARER | jeton d'accès JWT | / | 1 heure | HttpOnly ; Secure et SameSite=Strict en HTTPS, Lax en HTTP local |
REFRESH_TOKEN | jeton de rafraîchissement | /api/token | 30 jours | idem |
XSRF-TOKEN | jeton anti-CSRF | / | 1 heure, renouvelé | lisible par JavaScript, par construction ; mêmes Secure et SameSite |
Ils sont posés par JWTCookieSubscriber sur les réponses de connexion, de vérification 2FA, de lien magique et de rafraîchissement, et effacés sur POST /api/token/invalidate. Le corps de la réponse de connexion contient encore le jeton, pour les clients en ligne de commande.
Ordre de lecture du jeton
- Cookie
BEARER(navigateur). - En-tête
Authorization: Bearer …(scripts, outils, intégrations).
Le jeton de rafraîchissement est lu de la même façon : cookie REFRESH_TOKEN, sinon champ refresh_token du corps.
Protection CSRF
Un cookie part automatiquement avec toute requête vers le domaine. Pour qu'un site tiers ne puisse pas déclencher d'action au nom de l'utilisateur, les mutations (POST, PUT, PATCH, DELETE) authentifiées par cookie doivent porter l'en-tête X-CSRF-TOKEN égal au cookie XSRF-TOKEN (CsrfProtectionSubscriber). Le client Axios du frontend l'ajoute de lui-même.
Exemptées : connexion, vérification 2FA, rafraîchissement, déconnexion, mot de passe oublié, lien magique, santé et routes publiques (/api/public/, /api/cms/public/). Les appels authentifiés par l'en-tête Authorization ne sont pas concernés.
La vérification est active par défaut ; CSRF_ENABLED=false la coupe, en développement seulement.
Côté frontend
Le client Axios (frontend/src/services/api/client.ts) envoie les cookies (withCredentials: true) et garde le jeton d'accès en mémoire seulement. Au rechargement de la page, il appelle /api/token/refresh avant la première requête : le cookie REFRESH_TOKEN suffit à rétablir la session.
Vérifier
Dans les outils de développement du navigateur, onglet Application → Cookies : BEARER et REFRESH_TOKEN doivent apparaître avec la case HttpOnly cochée, et Secure sur les serveurs.
curl -si -X POST https://sig-preprod.ucp-pch.org/api/login \
-H "Content-Type: application/json" \
-d '{"email":"<EMAIL>","password":"<MOT_DE_PASSE>"}' | grep -i "^set-cookie"