Comment décoder et inspecter des jetons JWT

· 9 min de lecture

Les JSON Web Tokens (JWT) sont la manière la plus courante de gérer l'authentification dans les applications web modernes. Quand quelque chose va de travers avec l'auth, un utilisateur est déconnecté de manière inattendue, les permissions sont fausses, une API renvoie 401, décoder le JWT est généralement la première étape de débogage. Comprendre les trois parties d'un JWT, les revendications standard, les algorithmes avec lesquels il peut être signé, et les pièges courants transforme le débogage d'auth de vaudou en vérification de routine.

Une brève histoire de JWT

Les JWT ont été standardisés dans la RFC 7519 en mai 2015, après plusieurs années d'itération en brouillon à l'IETF. Le format a emprunté aux conceptions de jetons compacts précédentes (assertions SAML, simples cookies opaques) mais a ajouté deux choses qui leur manquaient : une forme JSON stricte lisible dans n'importe quel langage, et un encodage base64url-safe qui survivait aux paramètres d'URL, en-têtes HTTP et champs de formulaire sans nouvel échappement. Les spécifications complémentaires, JWS (RFC 7515) pour les signatures, JWE (RFC 7516) pour le chiffrement, et JWA (RFC 7518) pour les noms d'algorithme, forment ensemble la famille JOSE (JavaScript Object Signing and Encryption).

OAuth 2.0 et OpenID Connect ont adopté JWT comme format de jeton par défaut peu après, c'est pourquoi presque tous les fournisseurs d'auth modernes (Auth0, Okta, Cognito, Keycloak, Firebase, Supabase, Clerk) en émettent aujourd'hui. La combinaison de jetons autonomes et de back-ends sans état s'est avérée s'adapter très naturellement aux microservices et passerelles d'API. L'inconvénient est que les JWT sont notoirement faciles à mal utiliser, et la dernière décennie a produit un flux régulier de CVE dans des bibliothèques qui n'ont pas validé l'algorithme avec soin.

Ce qu'il y a dans un JWT

Un JWT a trois parties, séparées par des points :

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U

En-tête : contient l'algorithme (HS256, RS256, etc.) et le type de jeton.

{"alg": "HS256", "typ": "JWT"}

Charge utile : contient les revendications (assertions de données) sur l'utilisateur et le jeton.

{"sub": "1234567890", "name": "Alice", "exp": 1700000000}

Signature, un hash cryptographique qui vérifie que le jeton n'a pas été altéré. Vous ne pouvez pas la lire sans la clé de signature.

Chaque section est encodée en base64url, ce qui signifie qu'elle utilise - et _ au lieu de + et / et omet le bourrage = final. Base64url n'est pas du chiffrement ; coller juste le segment central dans n'importe quel décodeur révèle la charge utile. C'est par conception : les segments centraux sont conçus pour être lisibles par les services en chemin, la signature est la seule partie qui prouve l'authenticité.

Revendications JWT courantes

Les revendications standard sont enregistrées auprès de l'IANA et définies dans la RFC 7519. La plupart sont optionnelles, mais celles ci-dessous sont presque toujours présentes.

RevendicationNom completCe qu'elle contient
subSubject (sujet)ID ou identifiant utilisateur
expExpirationHorodatage Unix quand le jeton expire
iatIssued At (émis le)Horodatage Unix de création du jeton
issIssuer (émetteur)Qui a créé le jeton (votre serveur d'auth)
audAudienceÀ qui le jeton est destiné
nbfNot Before (pas avant)Le jeton n'est pas valide avant ce moment
jtiJWT IDIdentifiant unique du jeton
azpAuthorized PartyLa partie à qui le jeton a été émis (OIDC)
scope / scpPortées OAuthPermissions accordées, souvent séparées par espace
emailE-mailIdentifiant utilisateur OIDC standard
nameNomNom d'affichage (OIDC)
nonceNonceValeur OIDC de protection contre rejeu
kid (en-tête)Key IDQuelle clé de signature a été utilisée (pour lookup JWKS)

Au-delà du jeu standard, les applications ajoutent leurs propres revendications personnalisées (roles, tenant_id, feature_flags, permissions). Les noms de revendications personnalisés ne sont pas namespaces par défaut, ce qui signifie que deux services différents peuvent utiliser le même nom pour des choses différentes ; la convention OIDC de préfixer avec une URI (https://myapp.com/roles) évite la collision.

Comment décoder un JWT

  1. Collez votre jeton : entrez le JWT complet (format header.payload.signature) dans le décodeur. Les décodeurs basés navigateur le traitent localement, le jeton ne quitte jamais la page.
  2. Voir les sections décodées : l'outil affiche l'en-tête (algorithme), la charge utile (revendications), et la signature en JSON formaté, avec les horodatages affichés à la fois en entiers Unix et en dates lisibles.
  3. Vérifier les revendications : examinez le temps d'expiration, l'émetteur, le sujet, l'audience, et toute revendication personnalisée qui pilote votre logique d'autorisation.
  4. Comparer aux attentes : croisez l'émetteur avec le fournisseur d'auth que vous avez configuré, l'audience avec l'API à laquelle le jeton est envoyé, et toute revendication de rôle/portée avec les permissions que l'utilisateur devrait avoir.
  5. Test de voyage dans le temps : survolez iat, nbf, et exp pour voir si le jeton est actuellement valide, va bientôt expirer, ou a été émis il y a si longtemps que votre tolérance de dérive d'horloge ne le couvre plus.

Algorithmes de signature

Tous les JWT n'utilisent pas la même crypto. L'en-tête alg vous dit à quelle famille appartient la signature, et chacune a des propriétés de sécurité très différentes.

AlgorithmeFamilleType de cléQuand choisir
HS256HMACSecret partagéApps mono-service ; ne partagez jamais le secret entre équipes
HS384 / HS512HMACSecret partagéComme HS256 avec des digests plus longs
RS256RSAPaire de clés publique/privéeLe plus courant pour OIDC ; les vérificateurs n'ont besoin que de la clé publique
RS384 / RS512RSAPaire de clésComme RS256 avec clés plus grandes
PS256 / PS384 / PS512RSA-PSSPaire de clésRSA moderne, recommandé plutôt que RS pour nouveaux déploiements
ES256 / ES384 / ES512ECDSAPaire de clés à courbe elliptiqueClés plus petites que RSA, vérification plus rapide
EdDSAEd25519Paire de clés courbe d'EdwardsLe plus récent, le plus petit, le plus rapide ; pas encore universel
noneAucunAucuneInterdit en production ; certaines vieilles bibliothèques l'acceptent encore

Les algorithmes asymétriques (RS*, PS*, ES*, EdDSA) permettent à tout service de vérifier un jeton avec juste une clé publique, ce qui est pourquoi ils dominent OIDC. Symétrique (HS*) est correct dans une seule application mais devient un cauchemar à faire tourner ou distribuer entre plusieurs consommateurs.

Déboguer avec les JWT

Jeton expiré ? Vérifiez la revendication exp. Convertissez l'horodatage Unix en date lisible. S'il est dans le passé, le jeton a expiré et doit être rafraîchi. La plupart des bibliothèques JWT rejettent les jetons expirés par défaut ; si votre app les accepte, c'est un bug de sécurité.

Mauvaises permissions ? Cherchez les revendications de rôle ou portée dans la charge utile. Elles varient par implémentation mais ressemblent souvent à "role": "admin" ou "scope": "read write profile".

Problèmes d'identité utilisateur ? La revendication sub identifie l'utilisateur. Vérifiez qu'elle correspond à l'ID utilisateur attendu. Notez que certains fournisseurs utilisent des GUID opaques tandis que d'autres utilisent des adresses e-mail ; le décodeur vous montre exactement ce qui est là.

Jeton non accepté ? Vérifiez la revendication aud (audience). Si l'API attend une valeur d'audience spécifique et que le jeton en a une différente, il sera rejeté. Les décalages d'audience sont un symptôme courant de l'acheminement d'un jeton vers le mauvais service.

Erreurs 401 après déploiement ? Vérifiez la revendication iss (émetteur). Un nouveau tenant de fournisseur d'auth ou une clé de signature changée modifie l'URL de l'émetteur ; si votre vérificateur fait toujours confiance à l'ancien, tous les jetons paraissent invalides.

Problèmes de dérive d'horloge ? Si iat est légèrement dans le futur ou exp légèrement dans le passé, l'horloge de votre serveur peut dériver. La plupart des bibliothèques JWT autorisent quelques secondes de latitude ; sinon, une horloge synchronisée NTP corrige le problème.

Pièges courants

Alternatives à JWT

JWT est dominant mais pas la seule option. Chaque alternative échange des propriétés différentes.

MécanismeForceFaiblesse
JWT (JWS)Autonome, facile entre servicesNe peut être révoqué sans état supplémentaire
Jetons opaques + introspectionFacile à révoquer, cache les revendicationsChaque requête touche le serveur d'auth
Sessions côté serveurModèle le plus simple, révocation instantanéeDifficile à mettre à l'échelle entre services
PASETORemplacement plus sûr de JWT (pas de confusion alg)Écosystème plus petit
MacaroonsAtténuation intégrée (droits délégués)Support de bibliothèque limité
OAuth 2.0 + jetons d'accès JWTStandard de l'industrie pour les APISpec large, facile à mal implémenter
Jetons ID OIDCIdentité utilisateur standard + JWTSouvent confondu avec jetons d'accès
Certificats clients mTLSAuth la plus forte à la couche transportSurcoût de gestion des certificats

Pour la plupart des équipes, le choix est entre JWT et jetons opaques. JWT gagne quand la vérification doit être pas chère et hors ligne ; les jetons opaques gagnent quand la révocation doit être instantanée.

Vie privée et le décodeur

Le décodeur JWT tourne entièrement dans votre navigateur. Le jeton que vous collez est divisé, décodé en base64url, et le JSON est parsé et joliment imprimé sans aucune requête réseau. Il n'y a aucun journal des jetons qui ont été décodés, aucune analytique sur les revendications qu'ils contiennent, et aucun moyen pour quiconque de reconstruire pour qui vous étiez en train de déboguer. Les JWT contiennent souvent des identifiants utilisateur, adresses e-mail, noms de rôles internes, et IDs de tenant, exactement le genre de métadonnées que vous ne voulez pas envoyer au serveur d'un inconnu. Décoder côté client garde cette information sur votre machine, ce qui est le bon défaut pour toute tâche de débogage qui touche à l'authentification.

Questions fréquentes

Puis-je vérifier une signature JWT avec un décodeur ?

Non. La vérification de signature nécessite le secret de signature ou la clé publique, conservés sur votre serveur. Un décodeur vous montre ce qu'il y a dans le jeton, mais la vérification cryptographique doit se faire sur votre backend. Ne faites jamais confiance à un JWT non vérifié en production.

Est-il sûr de coller un JWT dans un outil en ligne ?

Oui, quand l'outil tourne dans votre navigateur. Les décodeurs dans le navigateur traitent le jeton localement, rien n'est envoyé sur un serveur. Évitez les outils qui font des requêtes réseau avec votre jeton.

Qu'est-ce que la revendication exp ?

La revendication exp (expiration) est un horodatage Unix indiquant quand le jeton expire. Après cette date, le jeton doit être rejeté. Vérifiez toujours cette revendication pour déboguer des problèmes d'authentification.

Les JWT peuvent-ils être chiffrés ?

Les JWT standards (JWS) sont signés mais pas chiffrés, n'importe qui peut décoder la charge utile. Les jetons JWE (JSON Web Encryption) sont chiffrés, mais moins courants. Ne mettez jamais de données sensibles (mots de passe, secrets) dans une charge utile JWT standard.

What is the alg none vulnerability?

Early JWT libraries accepted tokens with an alg header set to "none", meaning the signature could be omitted entirely. An attacker who set this header could forge any payload. Modern libraries reject "none" by default, but legacy systems may still be exposed; always allow-list the expected algorithm rather than trusting the header.

How should I store a JWT on the client?

HttpOnly secure cookies with SameSite=Lax (or Strict) are the safest default; they cannot be read by JavaScript, which mitigates XSS token theft. localStorage is convenient but vulnerable to any XSS bug. Never store long-lived JWTs alongside untrusted scripts.