Skip to content

Guide

Tokens JWT : comment décoder, vérifier et éviter les erreurs courantes

Trois segments base64url, une signature que vous devez vraiment vérifier, et un bug historique — alg: none — qui est encore livré dans certaines bibliothèques.

By Published

Un JWT est trois chaînes encodées en base64url jointes par des points. La première est des métadonnées, la seconde est les données qui vous intéressent vraiment, et la troisième est la signature qui prouve que les deux premières n’ont pas été modifiées. La plupart des bugs JWT viennent du traitement de la troisième partie comme optionnelle — ou d’une mauvaise lecture de ce que le format garantit en premier lieu.

La structure en trois segments

Un JWT ressemble à ceci :

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNzQ4NjQ4MDAwfQ.qZdfL_HxR_eRT3z3qZX7Rqv0kK7r0sQYMfRBlLcM2hI

Découpez sur les points, vous obtenez en-tête, charge utile, signature. Chacune des deux premières est un objet JSON qui a été encodé en base64url — une variante URL-safe de base64 qui remplace + par -, / par _, et omet le rembourrage. Collez n’importe quel token dans notre décodeur JWT pour voir les trois parties déployées en JSON brut.

L’en-tête

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

Deux champs. alg nomme l’algorithme de signature. typ identifie le token comme un JWT. Certains tokens incluent également kid (ID de clé) pour que le vérificateur sache quelle clé publique dans un ensemble de clés utiliser.

La charge utile

{
  "sub": "1234567890",
  "iat": 1748648000,
  "exp": 1748651600,
  "iss": "https://auth.example.com",
  "aud": "https://api.example.com"
}

N’importe quel objet JSON de votre choix. Les champs sont appelés claims. La RFC 7519 définit sept noms de claims « enregistrés » que vous devriez réutiliser quand leur signification correspond à la vôtre.

La signature

La signature est calculée sur base64url(en-tête) + « . » + base64url(charge utile) en utilisant l’algorithme et la clé indiqués par l’en-tête. C’est ce qui fait d’un JWT un JWT plutôt qu’une enveloppe base64 ordinaire.

Les claims enregistrés

  • iss (émetteur).Qui a créé le token. Généralement une URL identifiant votre service d’authentification.
  • sub (sujet).À qui le token se rapporte — généralement l’ID utilisateur.
  • aud (audience).Pour qui le token est destiné — l’URL API ou le nom du service. Un vérificateur qui ne correspond pas à l’audience attendue doit rejeter le token.
  • exp (expiration). Timestamp Unix après lequel le token est invalide. Les vérificateurs doivent rejeter les tokens expirés.
  • nbf (pas avant). Timestamp Unix avant lequel le token est invalide. Optionnel.
  • iat (émis à).Timestamp Unix de l’émission du token. Informatif.
  • jti (ID JWT). Un ID unique pour le token lui-même, utile pour la révocation explicite ou la prévention du rejeu.

HS256 vs RS256 vs ES256

HS256 (HMAC-SHA-256, symétrique)

La signature est un HMAC sur l’en-tête et la charge utile encodés en utilisant un secret partagé. Quiconque peut vérifier la signature peut aussi créer une nouvelle — la même clé fait les deux travaux.

Utilisez HS256 quand l’émetteur et le vérificateur sont la même partie. N’utilisez pas HS256 quand des tiers ont besoin de vérifier vos tokens — vous devriez partager le secret de signature, ce qui signifie qu’ils pourraient créer des tokens qui ressemblent aux vôtres.

RS256 (RSA-SHA-256, asymétrique)

La signature est une signature RSA utilisant la clé privée de l’émetteur. Les vérificateurs utilisent la clé publique de l’émetteur — publiée dans un endpoint JWKS — pour vérifier la signature. Les vérificateurs ne peuvent pas créer de tokens.

C’est le défaut pour l’identité fédérée : OpenID Connect, Auth0, Cognito, chaque flux « connexion avec X ».

ES256 (ECDSA sur P-256, asymétrique)

Même modèle de sécurité que RS256 mais avec des signatures sur courbe elliptique. Les avantages : taille de signature ~10× plus petite (64 octets contre 256), vérification plus rapide, et sécurité plus forte par bit. L’inconvénient : les implémentations ECDSA sont plus faciles à rater que RSA, et ont historiquement produit des bugs critiques.

EdDSA (Ed25519)

Plus récent que ES256, plus difficile à mal utiliser, le plus rapide des options asymétriques. Listé dans la RFC 8037 comme algorithme JWT mais pas universellement pris en charge — vérifiez votre stack avant d’adopter.

L’attaque alg: none

La spec JWT définit une valeur d’algorithme spéciale nonesignifiant « non signé. » Un token avec alg: none a un segment de signature vide.

En 2015, des chercheurs ont montré que plusieurs bibliothèques JWT honoraient le champ algdans l’en-tête comme instructions pour la vérification. Un attaquant pouvait prendre un token HS256 légitime, changer l’en-tête en alg: none, supprimer la signature, et la bibliothèque acceptait le token modifié comme valide.

La mitigation est de vérifier contre un algorithme attendu, pas l’algorithme que le token revendique :

// MAUVAIS — fait confiance à l'en-tête
jwt.verify(token, key);

// BON — fixe l'algorithme
jwt.verify(token, key, { algorithms: ["RS256"] });

Autres erreurs courantes

Faire confiance à l’en-tête kid sans validation

L’en-tête kid indique au vérificateur quelle clé utiliser depuis un ensemble de clés. Si vous utilisez kid aveuglément comme chemin de fichier ou clé de base de données, un attaquant peut fournir une valeur malveillante (../../etc/passwd ou injection SQL). Traitez toujours kid comme une clé de recherche opaque dans un ensemble connu, pas comme un chemin ou une requête.

Confusion d’algorithme (RS256 → HS256)

Certaines bibliothèques acceptent la clé publique pour la vérification RS256 mais l’acceptent aussi comme secret HMAC pour HS256. Un attaquant peut changer l’en-tête de RS256 à HS256, signer le token avec la clé publique RSA (publiquement connue) comme secret HMAC, et la bibliothèque vérifiera. Fixez l’algorithme.

Access tokens à longue durée de vie sans révocation

Les JWT sont sans état — le vérificateur ne contacte pas l’émetteur par requête. C’est tout le gain de performance, et tout le problème de révocation. Vous ne pouvez pas invalider un token divulgué avant son expsans maintenir une liste d’exclusion côté serveur.

Le pattern standard : access token à courte durée de vie (5-60 minutes) plus refresh token à longue durée de vie (jours à semaines) stocké côté serveur. Révoquez le refresh token lors de la déconnexion.

Mettre des secrets dans la charge utile

La charge utile est encodée en base64url, pas chiffrée. Quiconque possède le token peut lire chaque claim. Ne mettez pas de mots de passe, de clés API, de données personnelles soumises à une réglementation stricte, ou quoi que ce soit que vous n’écririez pas dans un journal de serveur. Si vous avez besoin de confidentialité, utilisez JWE à la place.

Stocker les JWT dans localStorage

localStorage est lisible par tout JavaScript sur votre origine, ce qui signifie que tout XSS devient un vol complet de token. Préférez les cookies sécurisés HTTP-only pour les tokens stockés dans le navigateur, avec une stratégie CSRF en plus.

Quand JWT est le mauvais outil

Les JWT résolvent un problème spécifique : un vérificateur a besoin de faire confiance à une revendication sans contacter l’émetteur. Ce problème existe genuinement dans l’identité fédérée et les microservices. Il n’existe généralement pas dans une application web propriétaire où le client et le serveur sont opérés par la même équipe.

Pour ce cas, une session côté serveur classique avec un cookie sécurisé HTTP-only est plus simple :

  • Immédiatement révocable.Supprimez la ligne de session, l’utilisateur est déconnecté.
  • Plus petit sur le réseau. Un ID de session fait 30 octets ; un JWT peut faire 500-2 000 octets.
  • Modèle de sécurité plus simple.Pas de bugs de confusion d’algorithme, pas de alg: none, pas de confusion sur le secret de la charge utile.

JWT vaut sa complexité quand vous avez plusieurs services qui ont besoin de faire confiance à l’identité utilisateur sans tous parler à un store de session central, ou quand vous émettez des tokens à des tiers — exactement le rôle que jouent les JWT dans un flux OAuth 2.0 / OpenID Connect.

Un template de vérification sécurisé

// Node.js, bibliothèque jsonwebtoken
import jwt from "jsonwebtoken";

function verifyToken(token: string): Payload {
  return jwt.verify(token, publicKey, {
    algorithms: ["RS256"],          // fixe l'algorithme
    issuer: "https://auth.example.com",   // fixe l'émetteur
    audience: "https://api.example.com",  // fixe l'audience
    clockTolerance: 5,              // petite marge pour le décalage d'horloge
  }) as Payload;
}

La conclusion honnête

Décoder un JWT est trivial — base64url, découper, analyser le JSON. Notre décodeur dans le navigateurle fait sans envoyer le token nulle part, ce qui est important car les tokens contiennent souvent des claims d’identification que vous ne voudriez pas coller sur un site tiers.

Vérifier un JWT est également simple, tant que vous fixez l’algorithme, validez iss, aud et exp, et ne faites jamais confiance à l’en-tête pour vous dire comment vérifier. Choisissez HS256 si l’émetteur et le vérificateur sont la même partie ; choisissez RS256 ou ES256 avec une bibliothèque vérifiée sinon. Et avant de vous tourner vers un JWT, vérifiez si un cookie de session ordinaire ferait l’affaire.

Frequently asked questions

Puis-je faire confiance à un JWT simplement parce qu’il a été décodé ?
Non — le décodage ne fait qu’analyser en Base64url l’en-tête et la charge utile. N’importe qui peut décoder un JWT ; la propriété de sécurité vient entièrement de la vérification de la signature contre une clé en laquelle vous avez confiance. Appelez toujours verify(token, key), pas decode(token), dans les chemins de code de production.
Un JWT est-il chiffré ?
Un JWT standard (techniquement un JWS) est signé, pas chiffré — la charge utile est lisible par quiconque possède le token. Si vous avez besoin de confidentialité, utilisez un JWE (JSON Web Encryption). Ne mettez jamais des mots de passe, des clés API ou d’autres secrets dans une charge utile JWT en supposant qu’ils sont cachés.
Qu’est-ce que l’attaque alg: none ?
Les premières bibliothèques JWT honoraient le champ alg dans l’en-tête comme instructions — y compris la valeur spéciale 'none', qui signifie 'pas de signature'. Un attaquant pouvait changer l’algorithme en none, supprimer le segment de signature, et présenter un token que la bibliothèque acceptait comme valide. Les bibliothèques modernes rejettent 'none' par défaut ou nécessitent un opt-in explicite.
Les access tokens doivent-ils être à courte ou longue durée de vie ?
Courts — quelques minutes à une heure au maximum. Les JWT ne peuvent pas être révoqués sans infrastructure (une liste d’exclusion explicite annule l’avantage sans état). Une courte durée de vie du token d’accès combinée à un refresh token à longue durée de vie stocké côté serveur est le pattern standard.
Quand JWT est-il vraiment le mauvais choix ?
Quand le client est une application web propriétaire et que vous contrôlez les deux côtés. Une session côté serveur classique avec un cookie sécurisé HTTP-only est plus simple, immédiatement révocable, plus petite sur le réseau, et immune à la plupart des bugs spécifiques aux JWT. JWT gagne en complexité dans les scénarios genuinement tiers — identité fédérée, microservices.
Quelle est la différence entre iat et nbf ?
iat (émis à) indique quand le token a été créé — informatif, pas une limite de validité. nbf (pas avant) est le moment le plus tôt auquel le token est valide — les vérificateurs doivent rejeter le token avant nbf. exp (expiration) est le moment le plus tardif auquel le token est valide. La plupart des tokens définissent iat et exp ; nbf est principalement utilisé lors de l’émission de tokens qui devraient devenir valides dans le futur.

Related

Published May 31, 2026