Vous vous connectez à une application, et celle-ci vous renvoie une longue chaîne de caractères commençant par « eyJ ». C'est très probablement un JWT (JSON Web Token) : une carte d'identité numérique signée, que votre navigateur ou votre application présente à chaque requête pour prouver qui vous êtes. Les JWT sont partout (API, authentification unique, applications mobiles) et mal compris : on les croit chiffrés, on les stocke n'importe où, on oublie de vérifier leur signature. Ce guide explique leur structure, les algorithmes de signature, ce qu'un JWT garantit (et ne garantit pas) et la liste de contrôle d'un serveur sérieux.
Décodez un jeton avec le décodeur JWT, regardez comment sont encodées ses parties avec l'encodeur Base64 et lisez son contenu avec le formateur JSON.
Les trois parties d'un JWT
Un JWT est composé de trois segments encodés en Base64URL (un Base64 sans « + », « / » ni « = ») et séparés par des points :
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
En-tête décodé : {"alg":"HS256","typ":"JWT"}. Contenu : {"sub":"1234567890","name":"John Doe","iat":1516239022}. La signature est un HMAC-SHA-256 de « en-tête.contenu » avec la clé your-256-bit-secret.
- L'en-tête indique l'algorithme de signature (
alg) et souvent l'identifiant de la clé (kid). - Le contenu porte les « revendications » (claims), c'est-à-dire les informations transportées.
- La signature prouve que en-tête et contenu n'ont pas été modifiés et qu'ils viennent du détenteur de la clé.
Les revendications standard
| Clé | Signification |
|---|---|
iss | Émetteur du jeton (issuer) |
sub | Sujet : en général l'identifiant de l'utilisateur |
aud | Destinataire prévu (service ou API) |
exp | Date d'expiration |
nbf | Date avant laquelle le jeton n'est pas valide |
iat | Date d'émission |
jti | Identifiant unique du jeton (détection de rejeu, révocation) |
Les dates sont des timestamps Unix en secondes (1516239022 correspond au 18 janvier 2018). Vérifiez-les avec le convertisseur de timestamp. Un jeton doit avoir une durée de vie courte (quelques minutes à quelques heures), complétée si besoin par un jeton de renouvellement stocké et révocable côté serveur.
Secret partagé ou clé publique : HS256 contre RS256
- HS256 / HS384 / HS512 (HMAC) : un secret sert à signer et à vérifier. Simple, adapté à un service qui émet et vérifie ses propres jetons. Le secret doit être long et aléatoire (au moins 256 bits pour HS256) et ne jamais quitter le serveur.
- RS256, PS256 (RSA) et ES256 (ECDSA) : une clé privée signe, une clé publique vérifie. Adapté quand un fournisseur d'identité signe et que de nombreux services vérifient, sans jamais pouvoir fabriquer un jeton. L'émetteur publie ses clés publiques au format JWK ; le champ
kidde l'en-tête désigne la bonne. none: aucun algorithme, aucune signature. Un serveur ne doit jamais accepter un jeton « non signé ».
Signé n'est pas chiffré
L'idée reçue la plus dangereuse est que le contenu d'un JWT est secret. Le Base64URL est un simple encodage : n'importe qui peut lire le contenu d'un jeton en le décodant, sans clé. La signature garantit l'intégrité (rien n'a été modifié) et l'origine, pas la confidentialité.
- N'y mettez rien de sensible : ni mot de passe, ni donnée de santé, ni numéro de carte. Préférez des identifiants opaques.
- Pour un contenu qui doit rester confidentiel, il existe une variante chiffrée, le JWE (RFC 7516).
- Ne collez pas de jeton de production dans un site tiers : utilisez des jetons de test ou expirés. Le décodeur d'Outilia travaille dans votre navigateur et n'envoie rien, mais la prudence est un bon réflexe.
Les erreurs classiques et la liste de contrôle
Les attaques visent presque toujours une validation incomplète côté serveur. Un serveur sérieux, suivant la RFC 8725 et l'OWASP :
- Vérifie toujours la signature avant de se fier au contenu (décoder ne suffit pas).
- Impose l'algorithme attendu au lieu de faire confiance à l'en-tête : refuse
none, et ne laisse pas un attaquant faire passer un jeton RS256 pour un HS256 signé avec la clé publique. - Contrôle
exp,nbf,issetaud: un jeton valide mais destiné à un autre service ne doit pas être accepté. - Utilise des secrets forts et des clés correctement protégées, avec rotation (
kid). - Prévoit la révocation : un JWT est valable jusqu'à son expiration. Pour déconnecter quelqu'un ou invalider un jeton volé, il faut une liste de révocation, des jetons à durée très courte ou un mécanisme de session côté serveur.
Côté client, stockez les jetons avec précaution : un jeton dans le localStorage est lisible par n'importe quel script injecté (faille XSS). Un cookie HttpOnly, Secure et SameSite est généralement plus sûr, au prix d'une protection contre le CSRF à prévoir. Transmettez toujours les jetons en HTTPS, et ne les placez pas dans une URL (elle est journalisée).
Un JWT est-il toujours le bon choix ? Pour une application web classique avec un seul serveur, une session classique (identifiant opaque stocké côté serveur) est souvent plus simple et plus facile à révoquer. Les JWT brillent surtout pour les API, les architectures distribuées et la délégation d'identité entre services.
Questions fréquentes
Un JWT est-il chiffré ?
Non, un JWT signé est simplement encodé en Base64URL : toute personne qui détient le jeton peut en lire le contenu. La signature garantit l'intégrité et l'origine, pas la confidentialité. Une variante chiffrée, le JWE, existe pour les contenus confidentiels.
Comment vérifier un JWT ?
Il faut recalculer la signature à partir de l'en-tête et du contenu avec la clé appropriée (le secret en HS256, la clé publique en RS256), la comparer à celle du jeton, puis contrôler les dates (exp, nbf), l'émetteur (iss) et le destinataire (aud).
Quelle différence entre HS256 et RS256 ?
HS256 utilise un secret partagé pour signer et vérifier. RS256 utilise une paire de clés : la clé privée signe, la clé publique vérifie, ce qui permet à de nombreux services de vérifier sans pouvoir fabriquer de jeton.
Où stocker un JWT dans un navigateur ?
Un cookie HttpOnly, Secure et SameSite est généralement plus sûr que le localStorage, qui est exposé aux scripts injectés. Dans tous les cas, utilisez HTTPS et des durées de vie courtes.
Comment révoquer un JWT ?
Un JWT est valide jusqu'à son expiration : pour le révoquer, il faut maintenir côté serveur une liste de jetons révoqués, ou utiliser des jetons à durée très courte avec un jeton de renouvellement révocable.