JSON Web Token (JWT) : Le guide complet

PrimFX Boris ('PrimFX') Le 19 juin 2020

Comment ça marche ?

Le principe de fonctionnement des JWT

La génération d’un JWT peut se résumer en 3 étapes assez élémentaires  :

  1. L’utilisateur se connecte depuis votre client qui va envoyer une requête HTTP au serveur (via l’API du serveur) avec, par exemple, un couple email/mot de passe
  2. Si les informations de connexion sont correctes, le serveur génère un jeton JWT
  3. Le serveur envoie le JWT généré au client, qui le conservera de son côté pour pouvoir le communiquer au serveur à chaque nouvelle requête

Schéma de la création d'un JWT

Ainsi, dès que le serveur reçoit une requête, si celle-ci contient un JWT, le serveur vérifiera la validité du JWT et saura quel utilisateur est à l’origine de la requête !

Schéma du fonctionnement d'un JWT

C’est aussi simple que ça 😃 L’idée, comme pour n’importe quelle méthode d’authentification, est simplement que le serveur puisse savoir « qui » (i.e. quel utilisateur) est à l’origine d’une requête. C’est pourquoi on appelle cela un jeton d’authentification. De plus, on pourra ajouter dans ce jeton des informations plus spécifiques sur les droits de l’utilisateur connecté : on pourra alors utiliser les JWT comme jetons d’autorisation (en plus de l’authentification) !

Concrètement, un JWT, c'est quoi ?

Petit rappel, JWT est l’acronyme de JSON Web Token, ce qui nous donne déjà un bon indice sur ce qu’est concrètement un JWT. Pour aller plus loin, JSON est lui-même l’acronyme de JavaScript Object Notation.

Ainsi, JWT prendra la forme d’un objet JSON qui contiendra un ensemble de paramètres et de valeurs. Voici à quoi pourrait ressembler l’objet, au format JSON, d’un utilisateur d’une application :

{“id”: “1234”, “username”: “PrimFX”, “email”: “primfx@example.com“}

Un JWT se décompose en 3 parties :

  • Le Header : il contient les informations d’en-tête de notre jeton décrites par les deux champs suivants :
    • alg: Indique l’algorithme utilisé pour signer (ou encrypter) le JWT. HS256 (HMAC + SHA256) est le plus communément utilisé.
    • typ: Indique le type d’objet dont il s’agit. Pour un JWT Token, ce sera systématiquement “JWT”
  • Le Payload : ce sont les données principales de notre jeton. Le Payload peut contenir des informations personnalisées (comme l’objet JSON présenté ci-dessus) ainsi que quelques paramètres prédéfinis optionnels appelés Claims (e.g. iss, exp, iat, etc.) : nous y reviendrons dans la section sur la sécurité des JWT.
  • La Signature : cette dernière partie permettra au serveur d’assurer la conformité et validité d’un jeton

Le JWT n’est donc ni plus ni moins qu’un objet JSON décomposé en 3 parties distinctes. Et puisqu’on ne peut pas faire transiter un objet JSON « brute » dans des requêtes HTTP entre client et serveur, les JWT sont toujours encodés en Base64 afin de pouvoir être communiqués sous forme de chaînes de caractères ! Ainsi, voici à quoi ressemblera notre JWT :

Exemple de jeton JWTA droite, on peut voir les trois sections Header, Payload et Signature de notre JWT (au format JSON). A gauche, il s’agit du JWT encodé en Base64 (où chaque section est indiquée par code couleur).

 

Nous reviendront un peu plus loin sur le principe de signature du JWT et sur sa sécurité 😉

Des jetons transmis à chaque requête

Finalement, le JWT sera transmis à chaque requête du client au serveur dans les Headers (en-têtes) des requêtes HTTP. Plus précisément, le JWT devra être transmis dans le champ Authorization des Headers de la requête. Il devra également respecter le format de chaîne de caractère “Bearer ”. Pour que ce soit plus parlant, voici un petit exemple de requête HTTP (en JavaScript) avec son en-tête contenant un JWT ainsi que quelques données :

// Code JavaScript : exécute une requête HTTP POST sur https://example.com en passant le JWT dans les Headers
fetch('https://example.com', {
  method: 'POST',
  body: JSON.stringify({
    param1: 'valeur1',
    param2: 'valeur2',
    etc: 'etc'
  }),
  headers: {
    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiMTIzNCIsInVzZXJuYW1lIjoiUHJpbUZYIiwiZW1haWwiOiJwcmltZnhAZXhhbXBsZS5jb20ifSwiaWF0IjoxNTkyNDIzNTAxfQ.OVj3A02xao5gyPgZY33b8QX7KtnkbmoFd6GbBnkwNVE'
  }
});

Comme vous le voyez ici, le JWT se passe belle et bien comme une simple chaîne de caractères, rien de bien compliqué.

A présent, voici un aperçu de la requête HTTP générée par ce code JavaScript — on retrouve bien le Authorization Bearer contenant notre JWT :

Exemple de requête HTTP avec JWT

 

Vous pouvez ne pas tenir compte des autres champs des Headers de la requête (Content-Type, Referer, etc.) : ils ont été générés automatiquement lors de l’envoi de la requête et ne nous concernent pas ici.

 

Le mot-clé Bearer dans le champ Authorization est simplement une sorte de convention de notation pour les JWT. Il permettra aux librairies JWT côté serveur de détecter si une requête contient un JWT ou non (i.e. si un Authorization Bearer est trouvé dans les Headers de la requête).


A propos de l'auteur

PrimFX
Boris ('PrimFX')

Je m'appelle Boris, j'ai 22 ans et je suis passionné d'informatique. Suite à mes études (Licence Informatique puis MSc Computer Science au Trinity College Dublin), je gère l'entreprise Single Quote co-fondée en 2019 et je profite de mon temps libre pour partager ma passion à travers des vidéos & articles 😃