Pendant longtemps, les cookies ont été utilisés pour iden­ti­fier les uti­li­sa­teurs. Cela fonc­tionne encore par­fai­te­ment aujourd’hui pour certaines ap­pli­ca­tions. Il est parfois cependant né­ces­saire de disposer d’un peu plus de flexi­bi­lité. C’est là qu’in­ter­vien­nent les JSON Web Token. Ce nouveau standard ouvert est de plus en plus pris en charge par les prin­ci­paux sites Web et ap­pli­ca­tions. Découvrez ce qu’est le standard JWT, son fonc­tion­ne­ment et ses ap­pli­ca­tions.

Qu’est-ce qu’un JSON Web Token ?

Un JSON Web Token est un access token (jeton d’accès) aux normes RFC 7519 qui permet un échange sécurisé de donnée entre deux parties. Il contient toutes les in­for­ma­tions im­por­tantes sur une entité, ce qui rend la con­sul­ta­tion d’une base de données superflue et la session n’a pas besoin d’être stockée sur le serveur (stateless session).

Les JSON Web Token sont par­ti­cu­liè­re­ment appréciés pour les opé­ra­tions d’iden­ti­fi­ca­tion. Les messages courts peuvent être chiffrés et four­nis­sent alors des in­for­ma­tions sûres sur l’identité de l’ex­pé­di­teur et si celui-ci dispose des droits d’accès requis. Les uti­li­sa­teurs eux-mêmes ne sont qu’in­di­rec­te­ment en contact avec les token, par exemple lorsqu’ils entrent un nom d’uti­li­sa­teur et un mot de passe dans un masque. La véritable com­mu­ni­ca­tion se fait entre les dif­fé­rentes ap­pli­ca­tions du côté serveur et client.

À quoi ressemble la structure d’un JSON Web Token ?

Un JWT signé se compose de trois parties codées en base64 et séparées par un point :

HEADER.PAYLOAD.SIGNATURE

Que sig­ni­fient ces trois com­po­santes ?

En-tête (Header)

L’en-tête, ou header, est en général composé de deux parties et fournit des in­for­ma­tions es­sen­tielles sur le token. Il contient le type de token et l’al­go­rithme de signature et/ou de chif­fre­ment utilisé. Un exemple de header de JWT :

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

Il est re­com­mandé d’entrer JWT pour le type. Il cor­res­pond au type de média « ap­pli­ca­tion/jwt » de l’IANA. Dans l’exemple ci-dessus, l’en-tête indique que HMAC-SHA256, abrévié « HS256 », est utilisé comme signature du token. Il existe d’autres méthodes courantes de chif­fre­ment, comme RSA avec SHA-256 (« RS256 ») et ECDSA avec SHA-256 (« ES256 »). Il est re­com­mandé de toujours utiliser un chif­fre­ment. Si les données ne re­quiè­rent pas un haut niveau de pro­tec­tion, il est possible d’indiquer « none » pour le chif­fre­ment. Les valeurs possibles sont stan­dar­di­sées par la JSON Web En­cryp­tion (JWE) selon le RFC 7516.

Le paramètre « cty » pour « Content Type » vient s’ajouter pour les JSON Web Token avec signature ou chif­fre­ment complexe. Il contient également la valeur « JWT ». Dans les autres cas, ce paramètre est laissé de côté.

Charge utile (Payload)

La charge utile du JSON Web Token est la partie qui contient les in­for­ma­tions qui doivent être trans­mises à l’ap­pli­ca­tion. C’est là que sont définis certains standards qui dé­ter­mi­nent quelles données doivent être trans­mises. Les in­for­ma­tions sont fournies en paire clé/valeur, les clés sont appelées « claims » dans les JWT. Il existe trois types de claims :

  • Les claims réservées sont des claims qui sont en­re­gis­trées dans le IANA JSON Web Token Claim Register. Leur objet est défini dans une norme. Comme exemple, on peut citer l’émetteur du token (« iss » pour Issuer), le domaine cible (« aud » pour Audience) et la date d’ex­pi­ra­tion (« exp » pour Ex­pi­ra­tion Time). On utilise des noms de claims courts afin de limiter au maximum la longueur des token.
  • Les claims publiques peuvent être définies librement. Il n’y a aucune li­mi­ta­tion. Afin que la sé­man­tique de la clé n’oc­ca­sionne pas de collision, il est né­ces­saire d’en­re­gis­trer pu­bli­que­ment la claim dans le IANA JSON Web Token Claim Register ou de lui attribuer un nom résistant aux col­li­sions.
  • Les claims privées sont conçus pour les in­for­ma­tions qui doivent être échangées spé­ci­fi­que­ment avec une ap­pli­ca­tion donnée. Les claims publiques con­tien­nent des in­for­ma­tions comme « Name » ou « E-mail » tandis que les claims privées sont plus spé­ci­fiques. Parmi les in­for­ma­tions standards pour ce genre de claim, on retrouve par exemple un « iden­ti­fiant uti­li­sa­teur » ou un « nom de dé­par­te­ment » concret. Il est né­ces­saire de faire attention à éviter les col­li­sions avec les claims réservées ou publiques dans le domaine de nom.

Toutes les claims sont op­tion­nelles. Vous n’avez donc pas à utiliser toutes les claims réservées. En règle général, la charge utile peut contenir autant de claims que né­ces­saire, il est cependant re­com­mandé de limiter les in­for­ma­tions du JWT au strict né­ces­saire. Plus le JWT est gros, plus il demande de res­sources pour être (dé)codé.

La charge utile peut donc être struc­tu­rée comme suit :

{ "sub": "123", "name": "Alice", "exp": 30 }

Signature

La signature d’un JSON Web Token est créée grâce au codage base64 de l’en-tête et de la charge utile et la méthode de signature/cryptage spécifiée. La structure est définie par la JSON Web Signature (JWS), une norme stan­dar­di­sée selon le RFC 7515. Pour que la signature fonc­tionne, il est né­ces­saire d’utiliser une clé secrète connue uni­que­ment de l’ap­pli­ca­tion source. Cette signature vérifie d’une part que le message ne sera pas modifié pendant le transfert. D’autre part, dans le cas d’un jeton signé avec une clé privée, il au­then­ti­fie également l’ex­pé­di­teur du JWT.

Plusieurs procédés sont dis­po­nibles en fonction de la sen­si­bi­lité des données :

  1. Aucune sécurité : comme expliqué plus haut, lorsque les données ne né­ces­si­tent pas de pro­tec­tion, la valeur « none » peut être indiquée dans l’en-tête. Dans ce cas, aucune signature n’est générée. Le JSON Web Token est alors uni­que­ment composé d’un en-tête et d’une charge utile. Sans sécurité, la charge utile est lisible en texte clair après le dé­chif­frage de la base64 et il n’est pas vérifié si le message vient du bon ex­pé­di­teur ou s’il a été modifié lors du transfert.
  2. Signature (JWS) : en règle générale, il suffit de vérifier si les données viennent du bon ex­pé­di­teur et si elles ont été modifiées. C’est là qu’in­ter­vient le schéma JSON Web Signature (JWS) qui assure que les messages n’ont pas été modifiés pendant le transfert et pro­vien­nent du bon ex­pé­di­teur. Grâce à cette procédure, la charge utile peut également être lue en texte clair après le dé­cryp­tage base64.
  3. Signature (JWS) et chif­fre­ment (JWE) : il est possible d’ajouter une JSON Web En­cryp­tion (JWE) au JWS. JWE chiffre le contenu de la charge utile qui est ensuite signé par JWS. Un mot de passe commun ou une clé privée est utilisé pour le chif­fre­ment du contenu. L’ex­pé­di­teur est également vérifié, le message est fiable et au­then­tique et la charge utile n’est plus lisible en texte clair après le dé­cryp­tage base64.

Le cryptage crée une séquence de ca­rac­tères ap­pa­rem­ment aléatoire :

{ 7WK5T79u5mIzjIXXi2oI9Fglmgivv7RAJ7izyj9tUyQ }
Note

Il est re­com­mandé d’utiliser un protocole SSL com­plé­men­taire en plus de chacun des procédés ci-dessus afin de protéger les données.

Comment fonc­tionne un JSON Web Token ?

Il est très aisé de com­prendre le fonc­tion­ne­ment d’un JSON Web Token en utilisant l’exemple d’une connexion uti­li­sa­teur. Une clé secrète est dé­ter­mi­née avant l’uti­li­sa­tion du JWT. Dès qu’un uti­li­sa­teur a entré avec succès ses données de connexion, le JWT est renvoyé avec la clé et stocké lo­ca­le­ment. Le transfert se fait par HTTPS afin de mieux protéger les données.

Lorsque l’uti­li­sa­teur veut accéder à des res­sources protégées comme une API ou un chemin d’accès protégé, le JWT sera envoyé par l’agent uti­li­sa­teur comme paramètre (par exemple « jwt » pour les GET-Requests) ou comme en-tête d’au­to­ri­sa­tion (pour POST, PUT, OPTIONS, DELETE). L’in­ter­lo­cu­teur peut dé­chif­frer le JSON Web Token et si le contrôle est réussi, exécuter la demande.

Note

Le JSON Web Token étant un iden­ti­fiant de connexion, vous n’avez pas besoin de conserver le token plus longtemps que né­ces­saire et vous n’avez pas besoin de stocker de données sensibles dans la mémoire du na­vi­ga­teur.

Dans quel cas utilise-t-on des JSON Web Token ?

Les JSON Web Token offrent un certain nombre d’avantages comparés aux méthodes tra­di­tion­nelles d’au­then­ti­fi­ca­tion et d’au­to­ri­sa­tion avec des cookies et sont pour cela utilisé dans les scénarios suivants :

  1. Ap­pli­ca­tions REST : dans les ap­pli­ca­tions REST, le JWT sécurise le protocole sans état en envoyant les in­for­ma­tions pour l’au­then­ti­fi­ca­tion di­rec­te­ment lors de la requête.
  2. Cross origin resource sharing : le JSON Web Token envoie les in­for­ma­tions lors du Cross Origin Resource Sharing. Cela présente un énorme avantage par rapport aux cookies, qui ne sont gé­né­ra­le­ment pas envoyés dans cette procédure.
  3. Uti­li­sa­tion de plusieurs fra­me­works : les JSON Web Token sont stan­dar­di­sés et donc po­ly­va­lents. Lors de l’uti­li­sa­tion de plusieurs Fra­me­works, ils per­met­tent de partager fa­ci­le­ment les données d’au­then­ti­fi­ca­tion.

À quoi ressemble une im­plé­men­ta­tion JWT ?

À l’aide d’un exemple de JWT, découvrez à quoi ressemble le token final. Pour ce faire, nous utilisons l’exemple d’en-tête que nous avons mentionné au début :

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

Une charge utile de JSON Web Token peut res­sem­bler à ceci :

{
	"sub": "0123456789",
	"name": "Jean Dupont",
	"admin": true
}

Pour obtenir la structure réelle du JWT (trois parties séparées par des points), l’en-tête et la charge utile doivent être codés en base64. Pour l’en-tête, cela ressemble à ceci :

base64Header = base64Encode(header)
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

Il en va de même pour la charge utile :

base64Payload = base64Encode(payload)
// eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

Il faut encore créer la signature. Dans l’en-tête, nous avons indiqué qu’il doit être signé avec HMAC-SHA256 :

signature = HS256(base64Header + '.' + base64Payload, ’secret’)
// dyt0CoTl4WoVjAHI9Q_CwSKhl6d_9rhM3NrXuJttkao

Pour finir, il faut ras­sem­bler ces trois com­po­santes et les séparer par un point.

Token = base64Header + '.' + base64Payload + '.' + signature
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.dyt0CoTl4WoVjAHI9Q_CwSKhl6d_9rhM3NrXuJttkao

La plupart des langages de pro­gram­ma­tion disposent gé­né­ra­le­ment d’une bi­blio­thèque pour générer les JSON Web Token, ce qui rend la mise en œuvre manuelle superflue.

Aller au menu principal