JWT n’est pas dangereux par nature, mais il devient fragile lorsque la validation est partielle. Beaucoup de bugs suivent le même schéma: le serveur décode le payload, lit l’utilisateur et oublie de vérifier l’algorithme, l’issuer, l’audience, l’expiration ou la politique de clé. Un token signé doit être traité comme un document de sécurité avec des règles strictes, pas comme une chaîne pratique contenant un user ID.
Ne laissez pas le token choisir l’algorithme
Le header annonce un algorithme, mais le serveur doit avoir une liste autorisée. Il ne doit pas accepter none, ni changer de famille de clés selon une valeur contrôlée par l’attaquant. La bibliothèque doit être appelée avec des options explicites.
Cette configuration paraît administrative, mais elle ferme une classe entière de vulnérabilités. Un wrapper interne bien conçu évite que chaque endpoint réinvente la validation.
Une signature valide ne suffit pas
Un token peut être correctement signé et ne pas être destiné à cette API. Il peut venir d’un autre environnement, d’un autre client ou d’un autre usage. Vérifier iss et aud empêche le rejeu d’un token légitime dans le mauvais contexte.
Les claims temporels sont tout aussi importants. Un token expiré ou pas encore valide doit être rejeté même si sa signature est correcte.
Le payload n’est pas un coffre
Base64URL ne chiffre rien. Les claims peuvent être lus par le porteur du token, par un outil de support qui le reçoit ou par un log trop bavard. Il faut éviter les données personnelles inutiles, secrets, droits trop détaillés et informations qui changent souvent.
La minimisation réduit exposition et taille. Si une API a besoin d’un état sensible ou frais, elle peut consulter un backend plutôt que tout figer dans le token.
Les expirations longues augmentent l’impact d’un vol
Un access token valable plusieurs jours donne beaucoup de temps à un attaquant. Des durées courtes limitent les dégâts, surtout si un refresh token contrôlé permet de renouveler proprement. La durée doit correspondre au risque de l’action.
Les endpoints administratifs ou financiers méritent des politiques plus strictes que des lectures peu sensibles. La commodité ne doit pas remplacer la révocation.
La révocation doit être conçue
Un JWT stateless ne disparaît pas du monde lorsqu’un utilisateur clique sur “déconnexion”. Si le produit exige invalidation immédiate après changement de mot de passe, perte d’appareil ou suspension, il faut ajouter de l’état: liste de révocation, version de session, introspection ou rotation de clés.
Il est acceptable de choisir l’attente jusqu’à expiration pour certains flux, mais cette décision doit être consciente et liée à une durée courte.
La rotation des clés doit être testée
Les clés changent pour maintenance ou incident. Un header kid peut sélectionner la clé publique, mais ce mécanisme doit être limité à une source fiable. Il ne doit pas permettre de lire des fichiers, d’appeler des URLs arbitraires ou d’accepter une clé fournie par l’attaquant.
Les consommateurs doivent gérer plusieurs clés pendant une période de transition. Tester cette rotation avant un incident évite de casser toute l’authentification au pire moment.
Le stockage côté client est un choix de menace
localStorage expose le token au JavaScript. Les cookies HttpOnly réduisent cette exposition mais nécessitent SameSite, CSRF et configuration HTTPS. Une application mobile a encore d’autres contraintes. Il n’existe pas de stockage parfait.
Quel que soit le choix, la prévention XSS, la réduction des claims et la redaction des logs restent obligatoires.
Les permissions doivent rester fraîches si nécessaire
Mettre tous les rôles dans un token peut créer des décisions obsolètes. Un utilisateur retiré d’un projet garde ses anciens claims jusqu’à expiration. Pour des actions sensibles, le service peut devoir vérifier l’état actuel en base.
Les scopes doivent être précis. Un claim vague comme admin devient vite trop large et difficile à auditer.
Observer les refus améliore la sécurité
Les logs doivent indiquer la cause du rejet sans stocker le token complet. Des métriques sur signatures invalides, issuers inconnus, audiences incorrectes et tokens expirés distinguent intégrations cassées et attaques. Les alertes doivent éviter le bruit tout en signalant les anomalies réelles.
Les environnements doivent rester séparés
Un token émis en staging ne devrait jamais être accepté en production. Cela demande des issuers, audiences, clés et domaines clairement séparés. Réutiliser un secret par confort rend les tests moins chers mais augmente fortement l’impact d’une fuite ou d’une mauvaise configuration.
Les bibliothèques de validation devraient être configurées par environnement et couvertes par tests. Une erreur de variable d’environnement ne doit pas transformer un service en vérificateur permissif.
Les incidents exigent un plan de rotation
Si une clé est compromise, l’équipe doit savoir comment retirer la clé, publier la nouvelle, invalider les tokens concernés et surveiller les refus attendus. Improviser cette séquence pendant l’incident augmente le risque de couper des utilisateurs légitimes ou de laisser une fenêtre ouverte trop longtemps.
La sécurité JWT est un ensemble: algorithmes fermés, claims validés, clés protégées, durées limitées, stockage réfléchi et observabilité. Omettre une pièce transforme une bonne idée en point faible.