Pourquoi Authentification JWT ?
L'authentification JWT (JSON Web Token) est un mécanisme d'authentification sécurisé qui permet de transmettre des informations entre les parties en forma de token crypté. Ce système est largement utilisé dans les applications web modernes et RESTful pour la gestion de l'authentification des utilisateurs sans avoir recours à des cookies ou des sessions server-side.
Un cas d'usage concret : Imaginez une application mobile qui permet aux utilisateurs de se connecter avec leur compte Google. Lorsque l'utilisateur clique sur le bouton "Se connecter avec Google", l'application récupère les informations de l'utilisateur et les transmet à un serveur backend qui vérifie la validité des informations. Si l'authentification est réussie, le serveur génère un JWT qui contient les informations de l'utilisateur et le signe avec sa clé secrète. L'application mobile stocke ensuite ce token dans le stockage local et utilise ce token pour chaque requête à l'API en tant que prélèvement d'authentification.
Prerequis
Pour suivre ce tutoriel, vous aurez besoin des connaissances suivantes :
- Connaissance de base du JavaScript
- Expérience avec un environnement backend (Node.js est recommandé)
- Familiarité avec les concepts de gestion des requêtes HTTP et des réponses
- Connaissance de la création et de la manipulation de tokens JWT
Les outils que vous devrez installer sont :
- Node.js (v14.0 ou plus tard)
- npm (node package manager)
Concepts fondamentaux
1. Concept : JWT Structure
Un JWT est une chaîne codée qui comprend trois parties séparées par des points (.) :
- Header : Metadonnées sur le type du token et l'algorithme utilisé pour sa signature.
- Payload : Informations encodées que vous souhaitez transmettre (clés/valeurs).
- Signature : Utilisée pour assurer l'intégrité du message.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Structure simplifiée :
{
"header": {
"alg": "HS256",
"typ": "JWT"
},
"payload": {
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
},
"signature": "..."
}
2. Concept : Algorithme de signature
L'algorithme utilisé pour signer le token détermine la sécurité du message. Les algorithmes couramment utilisés sont :
- HS256 (HMAC using SHA-256)
- RS256 (RSA using SHA-256)
- ES256 (ECDSA using SHA-256)
3. Concept : Génération et vérification du token
Pour générer un JWT, vous utilisez une bibliothèque comme jsonwebtoken en Node.js :
const jwt = require('jsonwebtoken');
// Générer un token JWT
const token = jwt.sign({ id: 123, username: 'user' }, 'secretKey', { expiresIn: '1h' });
console.log(token);
Pour vérifier un token JWT :
// Vérifier un token JWT
jwt.verify(token, 'secretKey', (err, decoded) => {
if (err) {
console.error('Token invalide:', err);
} else {
console.log('Token valide:', decoded);
}
});
Mise en pratique : projet fil rouge
Nous allons créer un simple API RESTful avec Express.js et JWT pour gérer les tâches d'un utilisateur.
Étape 1 : Initialisation du projet
Créez un nouveau dossier pour le projet et initialisez-le avec npm :
mkdir jwt-todo-app
cd jwt-todo-app
npm init -y
Installez les dépendances nécessaires :
npm install express jsonwebtoken bcryptjs cors body-parser
Étape 2 : Configuration de l'application
Créez un fichier app.js et configurez l'application Express :
const express = require('express');
const bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const app = express();
const port = 3000;
app.use(bodyParser.json());
app.use(cors());
// Mock user data
let users = [
{ id: 1, username: 'user', password: '$2a$10$dGhpcyBpcyBpbnNlY3JldA==' } // Password: "secret"
];
// Middleware pour vérifier le token JWT
function verifyToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (token == null) return res.sendStatus(401);
jwt.verify(token, 'secretKey', (err, user) => {
if (err) return res.sendStatus(403);
req.user = user;
next();
});
}
// Routes
app.post('/login', (req, res) => {
const { username, password } = req.body;
const user = users.find(u => u.username === username);
if (user && bcrypt.compareSync(password, user.password)) {
const token = jwt.sign({ id: user.id, username: user.username }, 'secretKey', { expiresIn: '1h' });
res.json({ token });
} else {
res.sendStatus(401);
}
});
app.get('/todos', verifyToken, (req, res) => {
const todos = [
{ id: 1, description: 'Faire les courses', completed: false },
{ id: 2, description: 'Nettoyer la chambre', completed: true }
];
res.json(todos);
});
app.post('/todos', verifyToken, (req, res) => {
const todo = req.body;
todos.push(todo);
res.status(201).json(todo);
});
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
Étape 3 : Test de l'API
Lancez le serveur :
node app.js
Vous pouvez tester les routes à l'aide d'un outil comme Postman ou cURL.
- Pour se connecter, envoyez une requête POST à
http://localhost:3000/loginavec un corps JSON contenantusernameetpassword. - Pour obtenir la liste des tâches, envoyez une requête GET à
http://localhost:3000/todosen incluant le token dans l'en-têteAuthorization.
Erreurs frequentes et debugging
1. Erreur : Token invalide
Message d'erreur :
jwt.verify(token, 'secretKey', (err, decoded) => {
if (err) console.error('Token invalide:', err);
});
Code incorrect :
const token = jwt.sign({ id: user.id }, 'wrongSecret');
Code correct :
const token = jwt.sign({ id: user.id }, 'secretKey');
2. Erreur : Token expiré
Message d'erreur :
jwt.verify(token, 'secretKey', (err, decoded) => {
if (err) console.error('Token invalide:', err);
});
Code incorrect :
const token = jwt.sign({ id: user.id }, 'secretKey', { expiresIn: '-1h' });
Code correct :
const token = jwt.sign({ id: user.id }, 'secretKey', { expiresIn: '1h' });
3. Erreur : Token non fourni
Message d'erreur :
jwt.verify(token, 'secretKey', (err, decoded) => {
if (err) console.error('Token invalide:', err);
});
Code incorrect :
const token = null;
jwt.verify(token, 'secretKey');
Code correct :
if (token == null) return res.sendStatus(401);
jwt.verify(token, 'secretKey', (err, decoded) => {
if (err) return res.sendStatus(403);
});
Pour aller plus loin
1. Authentification avec OAuth2
Pour une application web moderne, l'authentification avec OAuth2 est souvent préférée car elle permet aux utilisateurs de se connecter avec des comptes tiers comme Google, Facebook, etc.
Lire : OAuth 2.0
2. Authentification avec JWT et Firebase
Firebase est une plateforme complète pour le développement d'applications mobiles et web. Elle offre un service d'authentification sécurisé qui peut être utilisé avec des tokens JWT.
Lire : Firebase Authentication
3. Sécurité avancée des tokens JWT
Bien que JWT soient très sûrs, il est important de comprendre les risques associés à leur utilisation et d'adopter des pratiques de sécurité appropriées.
Lire : Securing APIs with JWT
Défi pratique
Créez une application web complète avec React.js ou Angular et utilisez la même API RESTful pour gérer les tâches d'un utilisateur. Assurez-vous que l'application utilise des tokens JWT pour l'authentification.