ArticleJetons et échanges

Qu'est-ce qu'un JSON Web Token (JWT) ?

Un format de jeton compact, signé et lisible en JSON : comment il est construit, comment le vérifier et pourquoi il porte la plupart des jetons de l'identité moderne.

Nom complet
JSON Web Token
Publié par
IETF, 2015
Repose sur
JWS, JWE, JWK et JWA (RFC 7515 à 7518)
Dans TOSIAM
ID tokens, access tokens JWT, assertions des clients
Sur cette page

Les JWT en bref#

Un JSON Web Token (JWT, prononcé « jot ») est un jeton compact qui transporte des informations sous forme d’objet JSON, protégées par une signature ou par un chiffrement. Celui qui le reçoit peut vérifier qui l’a émis et s’assurer que son contenu n’a pas été modifié, sans interroger l’émetteur.

Le format est défini par la RFC 7519, publiée par l’IETF en 2015. Il ne décrit pas un protocole, mais un conteneur : ce sont d’autres normes qui disent quoi y mettre et quand l’utiliser. L’ID token d’OpenID Connect, de nombreux access tokens OAuth 2.0 et les assertions qui servent à authentifier un client sont des JWT.

Pourquoi les JWT existent#

Un jeton classique est une référence opaque : une chaîne aléatoire qui ne veut rien dire en elle-même. Pour savoir à qui elle appartient et ce qu’elle autorise, le destinataire doit interroger le serveur qui l’a émise, à chaque requête.

Un JWT est autoporteur : il contient lui-même les informations utiles (l’émetteur, l’utilisateur, la date d’expiration, les droits accordés), et sa signature prouve qu’elles viennent bien de l’émetteur. Une API peut donc le valider seule, avec la clé publique de l’émetteur.

Le format a été pensé pour le web : il tient sur une seule ligne, ne contient que des caractères autorisés dans une URL ou un en-tête HTTP, et se lit avec n’importe quelle bibliothèque JSON.

Anatomie d’un JWT#

Un JWT signé se compose de trois parties encodées en Base64url et séparées par des points : l’en-tête, le contenu (payload) et la signature.

texte· Un JWT signé
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InJzYS0yMDI2In0.eyJpc3MiOiJodHRwczovL2xvZ2luLmV4YW1wbGUuZnIvdG9zaWFtL29hdXRoMiIsInN1YiI6ImNsYWlyZS5tYXJ0aW4ifQ.kLp3Q9vZ2mT8wXe1R4yN6bUcH0sJfA7dGiO5qVtMx2Ew

Décodées, les deux premières parties sont de simples objets JSON :

json· En-tête
{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "rsa-2026"
}
json· Contenu
{
  "iss": "https://login.example.fr/tosiam/oauth2",
  "sub": "claire.martin"
}
  • L’en-tête indique comment le jeton est protégé : l’algorithme (alg), le type de jeton (typ) et l’identifiant de la clé utilisée (kid).
  • Le contenu porte les claims, c’est-à-dire les affirmations de l’émetteur.
  • La signature est calculée sur les deux premières parties. Modifier un seul caractère de l’en-tête ou du contenu la rend invalide.

Les claims enregistrés#

La RFC 7519 définit quelques claims standard, tous facultatifs, que les autres normes reprennent :

Faites défiler le tableau
ClaimSignification
issL’émetteur du jeton (issuer).
subLe sujet : l’utilisateur ou le client que le jeton décrit.
audLe ou les destinataires prévus (audience). Un destinataire qui ne s’y reconnaît pas doit refuser le jeton.
expLa date d’expiration, en secondes depuis 1970.
nbfLa date avant laquelle le jeton n’est pas encore valable (not before).
iatLa date d’émission (issued at).
jtiUn identifiant unique, qui permet de détecter un rejeu ou de révoquer ce jeton précis.

À ces claims s’ajoutent ceux définis par chaque usage : nonce et auth_time pour un ID token, scope et client_id pour un access token, ou des claims propres à une organisation.

Signer ou chiffrer : JWS et JWE#

Un JWT est presque toujours signé, au format JWS (RFC 7515). Il peut aussi être chiffré, au format JWE (RFC 7516) : il compte alors cinq parties au lieu de trois, et seul le détenteur de la clé de déchiffrement peut lire son contenu. Pour obtenir les deux garanties, on signe d’abord, puis on chiffre le jeton signé.

Les algorithmes de signature, définis dans la RFC 7518, se répartissent en deux familles :

Faites défiler le tableau
FamilleExemplesCléQui peut vérifier ?
HMACHS256, HS384, HS512Un secret partagéSeulement ceux qui connaissent le secret, et qui pourraient donc aussi fabriquer des jetons.
AsymétriqueRS256, PS256, ES256, EdDSAUne paire de clésTout le monde, avec la clé publique ; seul l’émetteur détient la clé privée.
AucunenoneAucunePersonne : le jeton n’est pas protégé.

Dès qu’un jeton doit être vérifié par plusieurs services, un algorithme asymétrique s’impose : l’émetteur garde sa clé privée, et publie sa clé publique.

Vérifier un JWT#

Les clés publiques d’un émetteur sont publiées au format JWK (RFC 7517), regroupées dans un JWKS (JSON Web Key Set) accessible à une adresse fixe. Chaque clé porte un kid, que l’en-tête du jeton reprend pour désigner la clé à utiliser :

json· JWKS publié par l'émetteur (extrait)
{
  "keys": [
    {
      "kty": "RSA",
      "kid": "rsa-2026",
      "use": "sig",
      "alg": "RS256",
      "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc…",
      "e": "AQAB"
    }
  ]
}

Le parcours complet, de l’émission à la vérification, ressemble à ceci :

  1. Application vers TOSIAM Demande un jeton sur l’endpoint de jeton
  2. TOSIAM Construit les claims et les signe avec sa clé privée
  3. TOSIAM vers Application Renvoie le JWT
  4. Application vers API Appelle l’API avec Authorization: Bearer <jwt>
  5. API vers TOSIAM Télécharge le JWKS, s’il n’est pas déjà en cache
  6. API Retrouve la clé par son kid et vérifie la signature
  7. API Contrôle iss, aud, exp, puis les droits
  8. API vers Application Répond à la requête
Émission et vérification d’un JWT signé. L’API ne contacte l’émetteur que pour récupérer ses clés publiques, qu’elle garde en cache, et non à chaque requête.

Dans l’ordre, le destinataire :

  1. vérifie que l’algorithme de l’en-tête fait partie de ceux qu’il accepte pour cet émetteur ;
  2. vérifie la signature avec la bonne clé ;
  3. contrôle l’émetteur (iss), l’audience (aud) et les dates (exp, nbf), avec une faible tolérance d’horloge ;
  4. seulement ensuite, lit les autres claims pour prendre sa décision.

À quoi servent les JWT#

Faites défiler le tableau
UsageNormeRôle du JWT
ID tokenOpenID Connect CoreDécrire une authentification à l’application.
Access token au format JWTRFC 9068Porter les droits accordés, pour une API qui le valide elle-même. En-tête typ : at+jwt.
Authentification d’un clientRFC 7523, méthode private_key_jwtProuver l’identité d’une application par une assertion signée de sa clé privée, à la place d’un secret.
Grant type JWT BearerRFC 7523Échanger une assertion signée contre un access token.
Requête d’autorisation signéeRFC 9101Protéger les paramètres d’une demande d’autorisation, souvent avec PAR.

Les limites#

Le principal atout du JWT, être vérifiable sans l’émetteur, est aussi sa principale limite : un JWT valide le reste jusqu’à son expiration. Si un utilisateur se déconnecte ou si un jeton est volé, les services qui ne font que vérifier la signature continueront à l’accepter. D’où l’usage de durées de vie courtes, de quelques minutes à une heure, complétées par des refresh tokens.

Un JWT est aussi plus volumineux qu’une référence opaque (plusieurs centaines d’octets, parfois quelques kilo-octets), et son contenu est lisible par quiconque l’intercepte.

Bonnes pratiques#

La RFC 8725 rassemble les bonnes pratiques actuelles :

  • Fixez la liste des algorithmes acceptés côté destinataire, au lieu de faire confiance au champ alg du jeton. Refusez toujours none.
  • Ne mélangez jamais les familles pour une même clé : une bibliothèque qui accepte HS256 là où elle attend RS256 peut être trompée avec la clé publique utilisée comme secret HMAC.
  • Vérifiez systématiquement iss, aud et exp. Un jeton émis pour une autre application ne doit pas être accepté par la vôtre.
  • Distinguez les types de jetons par le champ typ ou par des claims dédiés, pour qu’un ID token ne soit jamais accepté comme access token.
  • Récupérez les clés depuis le JWKS de l’émetteur et gardez-les en cache ; rechargez-le quand un kid inconnu apparaît, ce qui arrive après une rotation de clés.
  • Gardez des durées de vie courtes et ne stockez dans le jeton que ce dont le destinataire a besoin.
  • Transmettez les JWT uniquement sur HTTPS : un jeton bearer vaut pour quiconque le présente.

Les JWT dans TOSIAM#

TOSIAM émet des JWT en tant que fournisseur OAuth 2.0 et OpenID Connect, et en accepte de la part des applications clientes.

Les clés publiques. Le fournisseur publie son JWKS à l’adresse /connect/jwk_uri sous son émetteur, par exemple https://login.example.fr/tosiam/oauth2/clients/connect/jwk_uri pour le royaume clients. Le JWKS contient les clés publiques RSA et EC du fournisseur, chacune identifiée par un kid.

Les ID tokens. L’algorithme de signature se choisit sur chaque agent OAuth 2.0, parmi ceux que le fournisseur annonce : HS256 à HS512, RS256 à RS512 et ES256 à ES512. La valeur par défaut d’un agent est HS256, qui signe avec le secret du client : seul ce client peut alors vérifier le jeton. Avec RS256 ou ES256, n’importe quel destinataire peut le vérifier grâce au JWKS. Un agent peut aussi demander que ses ID tokens soient chiffrés (JWE).

Les access tokens. Par défaut, TOSIAM délivre des access tokens opaques, dont le contenu est conservé dans le Core Token Store (CTS). Deux options produisent des JWT :

  • « Émettre les jetons d’accès sous forme de JWT », sur l’agent : le jeton reste enregistré dans le CTS, mais il est remis sous forme d’un JWT d’en-tête typ: at+jwt, conforme à la RFC 9068, dont le jti est l’identifiant CTS. Il contient notamment iss, sub, aud (l’identifiant du client), client_id, scope, iat, exp et auth_time. Cette option exige un algorithme asymétrique (RS ou ES) dans le réglage « Algorithme de signature des jetons OAuth2 » du fournisseur : la valeur par défaut, HS256, est refusée pour ces jetons.
  • Les jetons sans état (stateless), à activer à la fois dans le service OAuth2 Provider du royaume et sur l’agent : le JWT est lui-même le jeton, access comme refresh. TOSIAM enregistre tout de même leurs métadonnées dans le CTS, et la révocation passe par une liste noire, elle aussi conservée dans le CTS, qu’il consulte quand il valide un jeton. Une API qui ne fait que vérifier la signature n’a pas connaissance de cette liste.

Un script défini sur le fournisseur peut modifier les access tokens au moment de leur émission. La page Tokens compare les jetons stockés dans le CTS et les jetons sans état.

Les JWT reçus des clients. Une application peut s’authentifier auprès de TOSIAM par la méthode private_key_jwt : elle signe une assertion avec sa clé privée, et TOSIAM la vérifie avec la clé publique déclarée sur l’agent, fournie par une adresse JWKS (le choix par défaut), un JWKS recopié dans l’agent ou un certificat X.509. TOSIAM accepte aussi le grant type urn:ietf:params:oauth:grant-type:jwt-bearer : l’iss de l’assertion doit être l’identifiant d’un agent autorisé à utiliser ce grant type, les claims sub, aud et exp sont obligatoires, l’audience doit contenir l’endpoint de jeton, et les assertions non signées (none) ou signées par secret partagé (HS) sont refusées.

Pour aller plus loin#

Mis à jour le