Comprendre les jetons JWT : Un guide complet

· 12 min de lecture

Table des matières

Que sont les jetons Web JSON (JWT) ?

Les jetons Web JSON (JWT) sont devenus la norme de facto pour transmettre en toute sécurité des informations entre les parties dans les applications Web modernes. Définis par la RFC 7519, les JWT fournissent une méthode compacte et sûre pour les URL pour représenter les revendications à transférer entre deux parties.

Contrairement à l'authentification traditionnelle basée sur les sessions où le serveur maintient l'état, les JWT sont autonomes. Cela signifie que le jeton lui-même contient toutes les informations nécessaires pour vérifier l'identité et les permissions d'un utilisateur. Cette nature sans état rend les JWT particulièrement précieux dans les systèmes distribués, les architectures de microservices et les applications mobiles.

Les JWT servent deux objectifs principaux dans les applications modernes :

La beauté des JWT réside dans leur simplicité et leur polyvalence. Ils fonctionnent de manière transparente sur différents langages de programmation et plateformes, ce qui les rend idéaux pour les environnements hétérogènes où votre frontend peut être en React, votre backend en Node.js et votre application mobile en Swift ou Kotlin.

Conseil de pro : Bien que les JWT soient incroyablement utiles, ils ne sont pas une solution miracle pour tous les scénarios d'authentification. Comprendre quand utiliser les JWT par rapport aux sessions traditionnelles est crucial pour créer des applications sécurisées et évolutives.

Structure et anatomie détaillées du JWT

Un JWT se compose de trois parties distinctes séparées par des points (.), formant une structure qui ressemble à ceci : xxxxx.yyyyy.zzzzz. Chaque section a un objectif spécifique et ensemble, elles créent un ensemble d'informations inviolable.

L'en-tête

L'en-tête se compose généralement de deux parties : le type de jeton (JWT) et l'algorithme de signature utilisé, tel que HMAC SHA256 ou RSA. Ces informations indiquent à la partie réceptrice comment valider la signature du jeton.

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

L'en-tête est ensuite encodé en Base64Url pour former la première partie du JWT. Les algorithmes courants que vous rencontrerez incluent :

La charge utile

La charge utile contient les revendications, qui sont des déclarations sur une entité (généralement l'utilisateur) et des métadonnées supplémentaires. Les revendications sont classées en trois types :

Revendications enregistrées : Ce sont des revendications prédéfinies qui ne sont pas obligatoires mais recommandées pour assurer l'interopérabilité. Elles incluent :

Revendications publiques : Ce sont des revendications personnalisées que vous définissez pour votre application. Pour éviter les collisions, elles doivent être définies dans le registre IANA des jetons Web JSON ou utiliser des noms résistants aux collisions (comme des URI avec espace de noms).

Revendications privées : Revendications personnalisées créées pour partager des informations entre les parties qui acceptent de les utiliser. Ce ne sont ni des revendications enregistrées ni des revendications publiques.

{
  "sub": "1234567890",
  "name": "John Doe",
  "email": "[email protected]",
  "role": "admin",
  "iat": 1516239022,
  "exp": 1516242622
}

La charge utile est ensuite encodée en Base64Url pour former la deuxième partie du JWT.

Conseil rapide : Ne stockez jamais d'informations sensibles comme des mots de passe ou des numéros de carte de crédit dans les charges utiles JWT. Bien que les JWT soient signés, ils ne sont pas chiffrés par défaut, ce qui signifie que n'importe qui peut décoder et lire la charge utile.

La signature

La signature est créée en prenant l'en-tête encodé, la charge utile encodée, un secret (pour les algorithmes HMAC) ou une clé privée (pour RSA/ECDSA), et en les signant à l'aide de l'algorithme spécifié dans l'en-tête.

Par exemple, si vous utilisez HMAC SHA256, la signature serait créée comme ceci :

HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)

La signature garantit que le jeton n'a pas été modifié. Si quelqu'un modifie ne serait-ce qu'un seul caractère dans l'en-tête ou la charge utile, la vérification de la signature échouera.

Exemple de JWT complet

Lorsque vous assemblez les trois parties, vous obtenez un JWT complet qui ressemble à ceci :

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Vous pouvez décoder et inspecter n'importe quel JWT en utilisant notre outil de décodage JWT pour voir son en-tête, sa charge utile et vérifier sa signature.

Créer et utiliser les JWT en pratique

Créer des JWT est simple avec les bonnes bibliothèques. Explorons comment générer et utiliser des JWT dans différents langages de programmation et scénarios.

Créer des JWT en Node.js

La bibliothèque jsonwebtoken est le choix le plus populaire pour les applications Node.js :

const jwt = require('jsonwebtoken');

// Créer un jeton
const payload = {
  sub: user.id,
  email: user.email,
  role: user.role
};

const secret = process.env.JWT_SECRET;
const options = {
  expiresIn: '1h',
  issuer: 'myapp.com'
};

const token = jwt.sign(payload, secret, options);

// Vérifier un jeton
try {
  const decoded = jwt.verify(token, secret);
  console.log(decoded);
} catch (error) {
  console.error('Jeton invalide:', error.message);
}

Créer des JWT en Python

Les développeurs Python utilisent généralement la bibliothèque PyJWT :

import jwt
import datetime

# Créer un jeton
payload = {
    'sub': user.id,
    'email': user.email,
    'role': user.role,
    'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1),
    'iat': datetime.datetime.utcnow()
}

secret = os.environ.get('JWT_SECRET')
token = jwt.encode(payload, secret, algorithm='HS256')

# Vérifier un jeton
try:
    decoded = jwt.decode(token, secret, algorithms=['HS256'])
    print(decoded)
except jwt.ExpiredSignatureError:
    print('Le jeton a expiré')
except jwt.InvalidTokenError:
    print('Jeton invalide')

Créer des JWT en Java

Pour les applications Java, la bibliothèque java-jwt d'Auth0 est largement utilisée :

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

// Créer un jeton
Algorithm algorithm = Algorithm.HMAC256(secret);
String token = JWT.create()
    .withSubject(user.getId())
    .withClaim("email", user.getEmail())
    .withClaim("role", user.getRole())
    .withExpiresAt(new Date(System.currentTimeMillis() + 3600000))
    .withIssuer("myapp.com")
    .sign(algorithm);

// Vérifier un jeton
try {
    DecodedJWT jwt = JWT.require(algorithm)
        .withIssuer("myapp.com")
        .build()
        .verify(token);
} catch (Exception e) {
    System.out.println("Jeton invalide : " + e.getMessage());
}

Meilleures pratiques pour la génération de jetons

Lors de la création de JWT, suivez ces directives pour garantir la sécurité et la fiabilité :

Conseil de pro : Envisagez de mettre en œuvre un mécanisme de rafraîchissement de jeton à l'aide de jetons de rafraîchissement. Cela vous permet de garder les jetons d'accès de courte durée pour la sécurité tout en maintenant une bonne expérience utilisateur sans réauthentification fréquente.

Flux d'authentification JWT expliqué

Comprendre comment les JWT circulent dans votre application est crucial pour les implémenter correctement. Parcourons un flux d'authentification typique étape par étape.

Authentification initiale

  1. L'utilisateur soumet ses identifiants : L'utilisateur envoie son nom d'utilisateur et son mot de passe au point de terminaison d'authentification (généralement POST /api/auth/login).
  2. Le serveur valide les identifiants : Le serveur vérifie les identifiants par rapport à la base de données, en vérifiant que le hachage du mot de passe correspond.
  3. Le serveur génère un JWT : Lors d'une validation réussie, le serveur crée un JWT contenant l'identité de l'utilisateur et les revendications pertinentes.
  4. Le serveur renvoie le jeton : Le JWT est renvoyé au client, généralement dans le corps de la réponse. Certaines implémentations le définissent également comme un cookie HTTP uniquement.

Demandes ultérieures

  1. Le client inclut le jeton : Pour chaque demande ultérieure, le client inclut le JWT dans l'en-tête d'autorisation : Authorization: Bearer <token>
  2. Le serveur valide le jeton : Le serveur extrait le jeton, vérifie sa signature et vérifie son expiration.
  3. Le serveur traite la demande : Si le jeton est valide, le serveur extrait les informations de l'utilisateur de la charge utile et traite la demande en conséquence.
  4. Le serveur renvoie la réponse : Les données demandées ou le résultat de l'opération sont renvoyés au client.

Flux de rafraîchissement de jeton

Lorsque le jeton d'accès expire, le flux de rafraîchissement se déclenche :

  1. Le client détecte l'expiration : Le client reçoit une réponse 401 Non autorisé ou vérifie la revendication exp du jeton.
  2. Le client envoie le jeton de rafraîchissement : Le client envoie le jeton de rafraîchissement à un point de terminaison de rafraîchissement dédié (POST /api/auth/refresh).
  3. Le serveur valide le jeton de rafraîchissement : Le serveur vérifie le jeton de rafraîchissement et vérifie s'il a été révoqué.
  4. Le serveur émet un nouveau jeton d'accès : Un nouveau jeton d'accès est généré et renvoyé au client.
  5. Le client réessaie la demande d'origine : Le client utilise le nouveau jeton d'accès pour réessayer la demande échouée.

Flux de déconnexion

La déconnexion avec les JWT nécessite une attention particulière car les jetons sont sans état :

  1. Le client initie la déconnexion : L'utilisateur clique sur déconnexion, déclenchant une demande à POST /api/auth/logout.
  2. Le serveur invalide le jeton de rafraîchissement : Le serveur ajoute le jeton de rafraîchissement à une liste de révocation ou le supprime de la base de données.
  3. Le client supprime les jetons : Le client supprime les jetons d'accès et de rafraîchissement du stockage.
  4. Le client redirige : L'utilisateur est redirigé vers la page de connexion ou la zone publique.
Type de jeton Durée de vie typique Emplacement de stockage Objectif
Jeton d'accès 15 min - 1 heure Mémoire ou sessionStorage Autoriser les demandes API
Jeton de rafraîchissement 7 jours - 30 jours Cookie HTTP uniquement ou stockage sécurisé Obtenir de nouveaux jetons d'accès
Jeton d'identité Identique au jeton d'accès Mémoire Informations d'identité de l'utilisateur (OpenID Connect)

Conseil rapide : Implémentez le rafraîchissement automatique des jetons dans votre application cliente pour gérer l'expiration des jetons de manière transparente. Cela empêche les utilisateurs d'être déconnectés de manière inattendue

We use cookies for analytics. By continuing, you agree to our Privacy Policy.