Comment décoder un JWT
- Collez le jeton dans Jeton. Une ligne
Authorization: Bearer eyJ…entière fonctionne, tout comme des guillemets autour ou un jeton coupé sur plusieurs lignes. - Lisez le résultat. Les trois parties s’affichent dans des couleurs différentes, l’en-tête et le payload sont formatés, et Claims liste chaque claim avec sa signification. Les dates comme
expetiatapparaissent en heure locale, en UTC et en temps relatif du type « expire dans 1 heure ». - Pour vérifier la signature, collez le secret partagé ou la clé publique sous Vérifier la signature. Le libellé du champ suit l’
algdu jeton : Secret pour HS256/384/512, Clé publique pour tout le reste. - Lisez les avertissements. L’outil signale
alg: none, les jetons expirés, unnbfdans le futur, unexpmanquant, des dates écrites en millisecondes, et les en-têtes qui pointent vers des clés distantes (jku,x5u) ou embarquent leur propre clé (jwk).
Vous pouvez aussi ouvrir un jeton directement avec un lien comme /jwt-decoder/#token=eyJ…. La partie après # est un fragment d’URL, et les navigateurs n’envoient jamais les fragments au serveur.
Ce que contient un jeton
Un JWT signé (un JWS en forme compacte) se compose de trois chaînes Base64URL reliées par des points : header.payload.signature. Voici un vrai jeton HS256, émis le 1er janvier 2026 et valide une heure :
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiJ1c2VyLTQyIiwiYXVkIjoiYXBpLmV4YW1wbGUuY29tIiwiaWF0IjoxNzY3MjI1NjAwLCJleHAiOjE3NjcyMjkyMDB9.U3Gb12hN5Fnpi1rJ7nrkUzIEidkg-hPnbgiIpTah3R4
La première partie se décode en l’en-tête {"alg":"HS256","typ":"JWT"}. La deuxième est le payload :
{"iss":"https://auth.example.com","sub":"user-42","aud":"api.example.com","iat":1767225600,"exp":1767229200}
La troisième partie est un HMAC-SHA256 de 32 octets calculé sur les deux premières : modifier un seul caractère de l’en-tête ou du payload la casse. Presque tous les JWT commencent par eyJ, le Base64 de {". Les parties utilisent l’alphabet URL-safe (- et _) sans remplissage = ; comment les JWT utilisent Base64URL décode un jeton à la main, étape par étape.
JWS ou JWE : jetons signés ou chiffrés
La plupart des JWT sont des JWS : signés, lisibles par tous. Un JWE est chiffré et compte cinq parties au lieu de trois : header.encrypted_key.iv.ciphertext.tag. Son en-tête reste lisible et nomme l’algorithme de gestion de clé (alg, par exemple RSA-OAEP-256 ou dir) et l’algorithme de chiffrement du contenu (enc, par exemple A256GCM).
Collez un JWE ici et l’outil décode cet en-tête, affiche alg, enc et kid, et marque le payload comme chiffré. Le déchiffrer exige la clé privée du destinataire ou la clé partagée, et cet outil ne déchiffre pas les JWE. Si vous avez besoin d’un jeton dont les utilisateurs ne peuvent pas lire le payload, le JWE est le bon format ; mettre des secrets dans le payload d’un JWS revient à les mettre en clair, comme l’explique Base64 n’est pas du chiffrement.
Référence des claims JWT
Les sept premières lignes sont les claims enregistrés de la RFC 7519 ; les autres sont courants dans les jetons OpenID Connect et OAuth. Chaque valeur de date est une NumericDate : un nombre entier de secondes écoulées depuis le 1er janvier 1970 UTC, jamais de millisecondes.
| Claim | Nom | Ce qu’il faut vérifier |
|---|---|---|
iss | Émetteur | Qui a créé et signé le jeton. Doit correspondre à l’émetteur auquel vous faites confiance. |
sub | Sujet | L’utilisateur ou l’entité que concerne le jeton, souvent un ID utilisateur. |
aud | Audience | À qui le jeton est destiné. Une chaîne ou un tableau ; votre API doit refuser les jetons adressés à quelqu’un d’autre. |
exp | Date d’expiration | Passé ce moment, le jeton doit être refusé. |
nbf | Pas avant | Avant ce moment, le jeton n’est pas encore valide. |
iat | Émis le | Quand il a été émis. Utile pour limiter l’âge des jetons. |
jti | ID du JWT | Un identifiant unique, utilisé pour détecter le rejeu ou révoquer un seul jeton. |
azp | Partie autorisée | Le client OAuth auquel le jeton a été émis (OpenID Connect). |
scope, scp | Scopes | Les scopes OAuth accordés ; scp est l’écriture de Microsoft et d’Okta. |
nonce | Nonce | Lie un ID token OpenID Connect à la demande de connexion qui l’a réclamé. |
auth_time | Moment de l’authentification | Quand l’utilisateur s’est réellement connecté, ce qui peut être bien avant iat. |
roles, groups | Rôles, groupes | Données d’autorisation ajoutées par le fournisseur d’identité. |
tid, oid | Tenant, ID d’objet | Identifiants du tenant et de l’objet utilisateur dans Microsoft Entra ID. |
L’en-tête a ses propres paramètres : alg (l’algorithme de signature), typ (généralement JWT, ou at+jwt pour les access tokens OAuth), kid (la clé qui l’a signé) et cty (vaut JWT quand un jeton est imbriqué dans un autre).
Vérifier la signature : quelle clé coller
Seule la vérification de la signature indique d’où vient un jeton, et la clé nécessaire dépend de la famille d’algorithmes indiquée dans l’en-tête.
alg | Clé à coller | Longueur de la signature |
|---|---|---|
| HS256, HS384, HS512 | Le secret partagé. Réglez Le secret est sur Texte, Base64/Base64URL ou Hex selon la façon dont il est stocké ; un JWK oct fonctionne aussi. | 32, 48, 64 octets |
| RS256–RS512, PS256–PS512 | La clé publique RSA : PEM BEGIN PUBLIC KEY, PEM BEGIN RSA PUBLIC KEY, un certificat X.509, un JWK ou un JWKS. | Taille de la clé ; 256 octets pour RSA-2048 |
| ES256, ES384, ES512 | La clé publique EC sur P-256, P-384 ou P-521, sous l’une des formes ci-dessus. | 64, 96, 132 octets (r‖s brut) |
| EdDSA | Une clé publique Ed25519 en PEM ou en JWK OKP. | 64 octets |
Pour les jetons d’un fournisseur d’identité, les clés publiques se trouvent à l’adresse jwks_uri indiquée dans https://<issuer>/.well-known/openid-configuration. Cette page ne peut pas récupérer cette URL, car elle ne peut pas se connecter à d’autres serveurs : ouvrez-la dans un nouvel onglet et collez le JSON. Avec un JWKS, la clé est choisie d’après le kid ; si le jeton n’a pas de kid, toutes les clés compatibles sont essayées.
Les signatures ECDSA au format DER (en général 70 à 72 octets pour ES256 au lieu de 64) sont détectées, converties et signalées, car JWS exige r‖s brut et beaucoup de bibliothèques rejettent le DER. Une clé privée collée fonctionne aussi (la partie publique en est déduite), même si la vérification n’en a jamais besoin. ES256K et Ed448 ne sont pas pris en charge, car WebCrypto ne les propose pas.
Si un jeton HS256 échoue avec un secret dont vous êtes sûr, le secret est souvent encodé en Base64 quelque part dans votre configuration et le serveur le décode avant usage. Passez Le secret est sur Base64 et réessayez.
Pourquoi décoder un jeton ici est sûr
Un JWT dans un en-tête Authorization est un identifiant fonctionnel jusqu’à son expiration. Si vous collez un jeton de production actif dans une page web qui l’envoie à un serveur, l’exploitant de ce serveur peut le rejouer contre votre API, et de l’extérieur, vous ne pouvez généralement pas savoir si une page le fait.
Sur cette page, le décodage et la vérification de signature WebCrypto s’exécutent tous deux dans votre navigateur. La page applique aussi une Content Security Policy dont la directive connect-src n’autorise que /cdn-cgi/rum, où Cloudflare Web Analytics compte les pages vues : le navigateur bloque donc toute autre requête fetch, XHR, WebSocket ou beacon que la page pourrait tenter. Vous pouvez le vérifier vous-même : ouvrez les outils de développement sur l’onglet Réseau et collez un jeton, ou coupez le Wi-Fi une fois la page chargée et continuez à décoder.
Malgré cela, préférez des jetons de test ou sur le point d’expirer, et si un jeton de production a été collé à un endroit que vous ne contrôlez pas, révoquez la session.
Jetons expirés, nbf et décalage d’horloge
exp et nbf sont comparés à l’horloge du vérificateur, et les horloges dérivent. Un jeton émis par un serveur dont l’horloge avance de 30 secondes peut arriver avec iat et nbf dans le futur et être refusé comme « pas encore valide ». Les bibliothèques JWT acceptent donc une petite tolérance : leeway dans PyJWT, clockTolerance dans jsonwebtoken et jose.
Ce décodeur compare ces dates à l’horloge de votre appareil et décrit le résultat en toutes lettres : « a expiré il y a 2 jours » pour exp, « pas encore valide » avec le temps restant pour nbf, ou un avertissement indiquant que iat est dans le futur, ce qui met en cause l’horloge de l’émetteur. Une valeur comme 1767229200000 est signalée comme des millisecondes ; lue en secondes, elle tombe des dizaines de milliers d’années dans le futur, un bug courant quand le code utilise Date.now() au lieu de Math.floor(Date.now() / 1000).
Pour lire les claims dans le code sans vérifier la signature, la bibliothèque standard de Python suffit :
import base64, json
def b64url_decode(part):
return base64.urlsafe_b64decode(part + "=" * (-len(part) % 4))
header_b64, payload_b64, signature_b64 = token.split(".")
print(json.loads(b64url_decode(payload_b64)))
En Node.js, JSON.parse(Buffer.from(payload_b64, "base64url").toString("utf8")) fait la même chose. Pour les décisions d’autorisation, utilisez une bibliothèque qui vérifie la signature et fixe les algorithmes acceptés. Vous trouverez d’autres extraits sur les pages Python et Node.js.
Pour construire ou resigner un jeton de test, utilisez l’encodeur JWT. Un segment isolé peut être décodé seul avec le décodeur Base64URL.
FAQ
Puis-je décoder un JWT sans la clé secrète ?
Oui. L’en-tête et le payload ne sont que du JSON encodé en Base64URL : quiconque détient le jeton peut les lire. Le secret ou la clé publique ne sert qu’à vérifier que la signature est authentique.
Pourquoi le décodeur indique-t-il que la signature n'est pas valide ?
En général, la clé est mauvaise ou n’est pas sous la bonne forme. Pour HS256, vérifiez si le secret est stocké en Base64 ou en hex et modifiez Le secret est en conséquence. Pour RS256 ou ES256, assurez-vous que la clé publique correspond au kid du jeton ; si vous collez un JWKS entier, l’outil choisit la clé d’après le kid pour vous.
Comment savoir quand un JWT expire ?
Regardez le claim exp. C’est un nombre de secondes écoulées depuis le 1er janvier 1970 UTC, et le tableau des claims l’affiche en heure locale, en UTC et en temps relatif, comme « a expiré il y a 2 jours ». Un jeton sans exp n’expire jamais de lui-même.
Cet outil peut-il déchiffrer un JWE ?
Non. Pour un jeton chiffré en cinq parties, il décode l’en-tête protégé et affiche alg, enc et kid. Déchiffrer le payload exigerait la clé privée du destinataire ou la clé partagée.
Le jeton est-il envoyé quelque part quand je le colle ?
Non. Le décodage et la vérification s’exécutent dans votre navigateur avec JavaScript et WebCrypto, et la Content Security Policy de la page bloque toute requête réseau hormis le comptage des pages vues de Cloudflare.