Aller au contenu principal

Authentification JWT

Bemba authentifie les appels à l'API par des jetons JWT (LexikJWTAuthenticationBundle) et renouvelle la session par des jetons de rafraîchissement stockés en base (Gesdinet).

Jetons​

JetonDuréeOù il circule
Jeton d'accès (JWT signé RSA)1 heure (token_ttl: 3600)cookie BEARER (HttpOnly) ; en-tête Authorization: Bearer … accepté aussi
Jeton de rafraîchissement30 jourscookie REFRESH_TOKEN (HttpOnly, limité au chemin /api/token) ; table refresh_tokens

Le cookie est prioritaire ; l'en-tête sert aux scripts et aux outils en ligne de commande. En HTTPS, les cookies sont Secure et SameSite=Strict.

Routes​

RouteRôle
POST /api/loginConnexion (email, password) ; renvoie le jeton, le jeton de rafraîchissement et le profil, ou requires2FA si la double authentification est active pour le compte
POST /api/2fa/verifySeconde étape de connexion
POST /api/token/refreshNouveau jeton d'accès ; le jeton de rafraîchissement est remplacé à chaque usage
POST /api/token/invalidateDéconnexion : supprime le jeton de rafraîchissement et efface les cookies

Le frontend rafraîchit le jeton avant chaque requête quand il est absent de la mémoire (rechargement de page), expiré ou proche de l'expiration, et aussi après une réponse 401.

Protection CSRF​

Quand la requête est authentifiée par cookie, toute mutation (POST, PUT, PATCH, DELETE) doit porter l'en-tête X-CSRF-TOKEN, égal au cookie XSRF-TOKEN (motif « double submit cookie »). Les appels authentifiés par en-tête Authorization n'en ont pas besoin. Désactivable en développement seulement (CSRF_ENABLED=false).

Clés​

ÉlémentValeur
Emplacement~/pch-sig/backend/config/jwt/ sur le serveur, monté sur /app/config/jwt du conteneur backend : en lecture seule en production, en écriture en préproduction
PassphraseJWT_PASSPHRASE dans .env.prod
Créationl'entrypoint du backend sait générer une paire RSA 4096 si elles manquent ou si la passphrase ne les ouvre pas, à condition que le répertoire soit inscriptible (préproduction, développement) ; en production, les clés se créent sur l'hôte
Rotation des clés

La passphrase de .env.prod et les clés de l'hôte vont ensemble. Pour changer l'une, changer l'autre :

cd ~/pch-sig/backend/config/jwt
openssl genpkey -out private.pem -aes256 -algorithm rsa -pkeyopt rsa_keygen_bits:4096 -pass env:JWT_PASSPHRASE
openssl pkey -in private.pem -out public.pem -pubout -passin env:JWT_PASSPHRASE
sudo chown 82:82 private.pem public.pem # 82 = www-data dans l'image php:8.3-fpm-alpine
sudo chmod 600 private.pem && sudo chmod 644 public.pem

(JWT_PASSPHRASE exportée dans le shell le temps de la commande, puis reportée dans .env.prod.) Recréer ensuite le conteneur backend (up -d --force-recreate --no-deps backend). Les utilisateurs ne sont pas déconnectés : le jeton de rafraîchissement ne dépend pas de la clé, le premier appel répond 401, le frontend rafraîchit et rejoue la requête. Procédure complète de rotation des secrets : docs/ROTATION_SECRETS.md du dépôt.

Obtenir un jeton en ligne de commande​

curl -s -X POST https://sig-preprod.ucp-pch.org/api/login \
-H "Content-Type: application/json" \
-d '{"email":"<EMAIL>","password":"<MOT_DE_PASSE>"}' > token.json

curl -s https://sig-preprod.ucp-pch.org/api/users/me/permissions \
-H "Authorization: Bearer $(jq -r .token token.json)"

Ne jamais coller un jeton ni un mot de passe dans un ticket, un journal ou une conversation ; supprimer token.json après usage.

Dépannage​

SymptômeCauseAction
500 à la connexion, « Unable to create a signed JWT »clé privée illisible par www-data, ou passphrase qui ne correspond pas aux cléssur l'hôte, propriétaire 82:82 et mode 600 pour private.pem ; sinon vérifier la passphrase
Tous les utilisateurs déconnectéstable refresh_tokens vidée, ou cookies effacésse reconnecter
401 en bouclehorloge du serveur décalée, ou cookie bloqué par le navigateurdocker exec pch_backend date ; vérifier que le site est servi en HTTPS
403 « CSRF » sur une mutationen-tête X-CSRF-TOKEN absent ou périmérecharger la page (le cookie XSRF-TOKEN est réémis)
docker exec -u www-data pch_backend php bin/console debug:config lexik_jwt_authentication

Voir aussi​