Décodeur JWT

Analysez vos JSON Web Tokens : header, payload, claims et validité.

Token JWT

Guide complet : Comprendre et déboguer les JSON Web Tokens (JWT)

Pourquoi j'ai créé ce décodeur JWT

Après des années à implémenter des systèmes d'authentification basés sur JWT dans diverses applications (APIs REST, microservices, Single Page Applications), j'ai réalisé à quel point un bon outil de décodage est essentiel pour le débogage quotidien. Quand un utilisateur signale "je ne peux plus accéder à mon compte", la première chose que je fais est d'inspecter son token : est-il expiré ? Le claim "role" est-il correct ? L'audience correspond-elle ?

Ce décodeur vous permet d'analyser instantanément n'importe quel JWT, de visualiser son header et payload de manière structurée, et de vérifier les claims temporels (exp, iat, nbf) avec leur conversion en date lisible. Tout se passe dans votre navigateur — aucune donnée n'est envoyée à un serveur.

Qu'est-ce qu'un JWT et pourquoi est-il si populaire ?

Un JSON Web Token (JWT, prononcé "jot") est un standard ouvert (RFC 7519) permettant de transmettre des informations de manière sécurisée entre deux parties sous forme d'objet JSON signé. Contrairement aux sessions traditionnelles qui nécessitent un stockage côté serveur, les JWT sont "stateless" — toutes les informations nécessaires sont contenues dans le token lui-même.

Cette propriété stateless rend les JWT particulièrement adaptés aux architectures modernes : microservices, APIs RESTful, authentification cross-domain, et Single Sign-On (SSO). Un serveur n'a besoin que de la clé de vérification pour valider un token — pas d'accès à une base de données de sessions.

Anatomie détaillée d'un JWT

Un JWT se compose de trois parties séparées par des points (.), chacune encodée en Base64URL :

xxxxx.yyyyy.zzzzzheader.payload.signature

📝 Header (En-tête JOSE)

Le header contient les métadonnées du token : le type ("typ": "JWT") et l'algorithme de signature ("alg": "HS256", "RS256", "ES256", etc.). C'est une information critique — elle indique au récepteur comment vérifier la signature. Certains headers incluent aussi "kid" (key ID) pour identifier quelle clé utiliser dans un système avec rotation de clés.

Exemple : {"alg": "RS256", "typ": "JWT", "kid": "abc123"}

📦 Payload (Charges utiles / Claims)

Le payload contient les "claims" — les affirmations que le token fait sur l'utilisateur ou le contexte. Il existe des claims réservés (iss, sub, exp...), des claims publics (définis dans le registre IANA), et des claims privés (spécifiques à votre application comme "role", "permissions", "user_id").

ATTENTION : Le payload est encodé en Base64, pas chiffré ! N'importe qui peut le décoder. Ne mettez JAMAIS de mots de passe, clés API, ou données sensibles dans un JWT.

🔐 Signature (Vérification d'intégrité)

La signature est calculée en prenant le header encodé, le payload encodé, et une clé secrète (ou privée), puis en appliquant l'algorithme spécifié dans le header. Elle garantit que le token n'a pas été altéré — si un seul bit du header ou payload change, la signature ne correspondra plus.

Formule : HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

Les claims réservés (Registered Claims) en détail

Ces claims sont définis dans la RFC 7519 et ont une sémantique précise. Leur utilisation n'est pas obligatoire mais fortement recommandée :

  • iss (Issuer) : Identifie l'émetteur du token. Généralement l'URL de votre serveur d'authentification (ex: "https://auth.example.com"). Permet de rejeter les tokens émis par des sources non autorisées.
  • sub (Subject) : Le sujet du token, généralement l'identifiant unique de l'utilisateur (UUID, email, etc.). Doit être unique dans le contexte de l'issuer.
  • aud (Audience) : Les destinataires prévus du token. Peut être une chaîne ou un tableau. Un service ne doit accepter que les tokens où son identifiant apparaît dans l'audience.
  • exp (Expiration Time) : Timestamp Unix après lequel le token est invalide. Vérification critique côté serveur — un token expiré doit être systématiquement rejeté.
  • nbf (Not Before) : Timestamp Unix avant lequel le token n'est pas valide. Utile pour les tokens programmés à l'avance.
  • iat (Issued At) : Timestamp de création du token. Permet de calculer l'âge du token et potentiellement de rejeter les tokens trop anciens.
  • jti (JWT ID) : Identifiant unique du token (généralement un UUID). Permet d'éviter les attaques par rejeu en maintenant une liste des jti utilisés.

Algorithmes de signature : HS256 vs RS256 vs ES256

🔑 HS256 (HMAC + SHA-256) — Symétrique

Utilise une clé secrète unique pour signer ET vérifier. Simple à implémenter, performant. Inconvénient majeur : la clé secrète doit être partagée avec tous les services qui doivent vérifier les tokens. Risque de compromission si un service est piraté.

Cas d'usage : Applications monolithiques, environnements où tous les services sont de confiance.

🔐 RS256 (RSA + SHA-256) — Asymétrique

Utilise une paire clé privée (pour signer) / clé publique (pour vérifier). Seul le serveur d'authentification détient la clé privée. Les services n'ont besoin que de la clé publique, qui peut être distribuée librement (souvent via JWKS endpoint).

Cas d'usage : Microservices, SSO, APIs publiques, OAuth2/OIDC.

🛡️ ES256 (ECDSA + SHA-256) — Courbes elliptiques

Asymétrique comme RS256, mais basé sur les courbes elliptiques. Signatures plus courtes et calcul plus rapide que RSA pour un niveau de sécurité équivalent. De plus en plus recommandé pour les nouvelles implémentations.

Cas d'usage : Applications mobiles, IoT, environnements avec contraintes de bande passante.

Sécurité JWT : les pièges à éviter absolument

  • Vulnérabilité "alg: none" : Certaines bibliothèques mal configurées acceptent des tokens sans signature si le header indique "alg": "none". TOUJOURS vérifier l'algorithme côté serveur et rejeter "none".
  • Confusion d'algorithme : Un attaquant peut changer "RS256" en "HS256" et utiliser la clé publique (connue) comme clé secrète HMAC. Vérifiez toujours que l'algorithme correspond à celui attendu.
  • Clés faibles : Pour HS256, utilisez une clé d'au moins 256 bits (32 caractères) générée aléatoirement. Une clé faible peut être brute-forcée.
  • Stockage non sécurisé : localStorage est accessible par n'importe quel script JS sur la page (vulnérable au XSS). Préférez les cookies httpOnly + Secure + SameSite.
  • Absence de vérification d'expiration : Vérifiez TOUJOURS exp côté serveur. Ne faites jamais confiance au client pour cette vérification.
  • Données sensibles dans le payload : Le payload est LISIBLE par tous. Jamais de mots de passe, secrets, ou données personnelles sensibles.

Bonnes pratiques d'implémentation

  • Durées d'expiration courtes : 15 minutes à 1 heure pour les access tokens. Utilisez des refresh tokens (7-30 jours) stockés de manière sécurisée pour renouveler sans ré-authentification.
  • Rotation des clés : Prévoyez un mécanisme de rotation de clés (JWKS avec kid) pour pouvoir changer de clé sans invalider tous les tokens existants.
  • Validez tous les claims pertinents : iss, aud, exp au minimum. Ne faites jamais confiance aveuglément au contenu du token.
  • Utilisez des bibliothèques éprouvées : jsonwebtoken (Node.js), PyJWT (Python), java-jwt (Java), etc. N'implémentez pas votre propre vérification de signature.
  • Loggez les échecs d'authentification : Tokens expirés, signatures invalides, audiences incorrectes... Ces logs sont précieux pour détecter les attaques.

Traitement 100% local : votre sécurité est préservée

Ce décodeur fonctionne entièrement dans votre navigateur. Le token que vous collez n'est jamais envoyé à nos serveurs — le décodage Base64 et l'analyse JSON s'effectuent en JavaScript côté client. Vous pouvez le vérifier dans l'onglet Réseau de vos DevTools : aucune requête réseau n'est émise lors du décodage.

Cela dit, pour des tokens de production contenant des informations sensibles (même si elles ne devraient pas y être), préférez des outils complètement hors ligne comme la commande jwt-cli ou des scripts locaux.

Questions fréquentes sur les JWT

Est-il sécurisé de décoder un JWT de production ici ?

Oui, du point de vue de la transmission des données. Le décodage s'effectue entièrement dans votre navigateur — aucune donnée n'est envoyée à nos serveurs. Vous pouvez vérifier dans l'onglet Réseau des DevTools.

Cependant, gardez à l'esprit plusieurs points :

  • Le payload d'un JWT n'est pas chiffré, juste encodé en Base64. N'importe qui avec accès au token peut le décoder — c'est par conception.
  • Si votre navigateur est compromis (extension malveillante, keylogger), le token pourrait être capturé.
  • Pour les tokens très sensibles, préférez des outils hors ligne (jwt-cli, scripts Python locaux).

La signature n'est pas vérifiable sans la clé secrète/publique — nous ne pouvons que décoder le contenu, pas confirmer son authenticité.

Quelle est la différence entre HS256, RS256 et ES256 ?

Ces algorithmes diffèrent par leur mécanisme cryptographique :

  • HS256 (HMAC-SHA256) : Algorithme symétrique. Une seule clé secrète pour signer ET vérifier. Simple mais la clé doit être partagée avec tous les services vérificateurs — risque si un service est compromis.
  • RS256 (RSA-SHA256) : Algorithme asymétrique. Clé privée pour signer (gardée secrète), clé publique pour vérifier (distribuée librement). Idéal pour les microservices et OAuth2.
  • ES256 (ECDSA-SHA256) : Également asymétrique, basé sur les courbes elliptiques. Signatures plus courtes que RSA, calcul plus rapide. Recommandé pour les nouvelles implémentations.

Ma recommandation : RS256 ou ES256 pour les systèmes distribués et APIs publiques. HS256 uniquement pour les applications monolithiques simples où la clé peut rester sur un seul serveur.

Comment invalider (révoquer) un JWT avant son expiration ?

C'est le talon d'Achille des JWT : par conception, ils sont stateless et auto-porteurs — une fois émis, ils sont valides jusqu'à expiration. Voici les stratégies pour contourner ce problème :

  1. Durées d'expiration très courtes (5-15 min) avec refresh tokens révocables. Le refresh token est stocké en base et peut être supprimé à tout moment.
  2. Blacklist / Blocklist : Stockez les jti des tokens révoqués dans Redis ou en base. Vérifiez à chaque requête. Inconvénient : perd l'avantage stateless.
  3. Token versioning : Stockez une "version" par utilisateur. Incluez cette version dans le token. Quand vous changez la version utilisateur, tous ses anciens tokens deviennent invalides.
  4. Rotation de clé : Changer la clé de signature invalide TOUS les tokens existants — solution nucléaire à utiliser en dernier recours.

En pratique, la combinaison "access tokens courts + refresh tokens révocables" est la solution la plus équilibrée.

Où stocker un JWT côté client : localStorage, sessionStorage ou cookies ?

C'est l'un des débats les plus contestés en sécurité web. Chaque option a ses compromis :

  • localStorage / sessionStorage : Accessible par n'importe quel JavaScript sur la page. Vulnérable au XSS — si un script malveillant s'exécute, il peut voler le token.
  • Cookies httpOnly + Secure + SameSite=Strict : Protégés contre XSS (JavaScript ne peut pas lire un cookie httpOnly). Mais vulnérables au CSRF — atténuable avec des tokens CSRF ou SameSite.

Ma recommandation :

  • Applications web classiques : cookies httpOnly + mesures anti-CSRF
  • SPAs avec backend sur même domaine : cookies httpOnly
  • SPAs avec API sur domaine différent : localStorage + CSP strict + validation rigoureuse des inputs (prévention XSS)

Dans tous les cas, une bonne politique CSP (Content Security Policy) est essentielle.

Quelle durée d'expiration choisir pour un JWT ?

C'est un compromis entre sécurité et expérience utilisateur :

  • Applications bancaires / haute sécurité : Access token 5-15 minutes max. Refresh token 1-24 heures, avec ré-authentification pour les opérations sensibles.
  • Applications grand public : Access token 30 min à 1 heure. Refresh token 7-30 jours (avec option "Se souvenir de moi").
  • APIs internes / M2M : Peut être plus long (heures) si le risque de compromission est faible et la rotation de clés est en place.

Implémentez toujours le rafraîchissement transparent : le client renouvelle automatiquement l'access token via le refresh token, sans que l'utilisateur ne s'en aperçoive.

Le refresh token doit être révocable côté serveur (stocké en base) pour permettre la déconnexion forcée.

Peut-on modifier le contenu d'un JWT ?

Techniquement oui, pratiquement non. Le payload est simplement encodé en Base64 — n'importe qui peut le décoder, modifier, et ré-encoder.

Cependant, la signature est calculée sur le header + payload originaux. Si vous modifiez quoi que ce soit et présentez le token à un serveur qui vérifie correctement la signature, il sera rejeté car la signature ne correspondra plus.

Attention aux vulnérabilités connues :

  • Algorithme "none" : Certaines bibliothèques mal configurées acceptent "alg": "none", permettant de supprimer la signature. Vérifiez toujours l'algorithme côté serveur.
  • Confusion d'algorithme : Changer RS256 en HS256 et utiliser la clé publique comme secret HMAC. Le serveur doit toujours forcer l'algorithme attendu.

JWT vs Sessions traditionnelles : quand utiliser quoi ?

Les deux approches ont leurs forces :

JWT (stateless) est préférable pour :

  • APIs RESTful et microservices (pas de stockage de session partagé)
  • Authentification cross-domain / Single Sign-On (SSO)
  • Applications mobiles et SPAs avec APIs
  • Systèmes distribués à haute échelle

Sessions serveur (stateful) sont préférables pour :

  • Applications web traditionnelles (MVC, server-rendered)
  • Quand la révocation immédiate est critique (sécurité haute)
  • Si vous avez déjà une infrastructure de gestion de sessions
  • Applications simples avec peu de trafic

En réalité, beaucoup de systèmes utilisent un hybride : JWT pour les access tokens stateless, avec refresh tokens stockés en base (stateful) pour permettre la révocation.

Mon token affiche "Token expiré" — que faire ?

Cela signifie que le claim exp (expiration) du token est antérieur à l'heure actuelle. Comportement normal et attendu — les tokens doivent expirer !

Si vous êtes utilisateur :

  • L'application devrait automatiquement rafraîchir votre token via un refresh token
  • Si ce n'est pas le cas, déconnectez-vous et reconnectez-vous pour obtenir un nouveau token

Si vous êtes développeur et déboguez :

  • Vérifiez que votre client implémente correctement le rafraîchissement automatique
  • Vérifiez la synchronisation horaire entre le serveur émetteur et le serveur vérificateur
  • Considérez d'ajouter une "clock skew tolerance" (marge de quelques secondes) pour les différences d'horloge