Fluxes OAuth 2.0 Code d'autorisation, PKCE et identifiants du client
Un guide pour les développeurs sur le choix du bon flux OAuth 2.0. Aborde le flux d'autorisation (applications web), PKCE (applications web et mobiles) et les credentials du client (serveur à serveur), avec des exemples de code fonctionnels et les erreurs qui vous rattrapent plus tard.
Trois flux couvrent 95% de cas réels d'utilisation OAuth 2.0. La spécification définit davantage, mais le reste est déprécié, cas limite ou les deux. Choisissez le bon flux dès le départ, et vous évitez un refactoring douloureux lorsque les exigences d'authentification changent.
| Flux | Quand les utiliser | Est-ce que l'utilisateur est impliqué ? | A-t-il besoin d'un client_secret ? |
|---|---|---|---|
| Code d'autorisation | Application web avec un serveur backend | Oui | Oui — reste sur le serveur |
| Code d'autorisation + PKCE | Application SPA, application mobile, tout client public | Oui | Non |
| Identifiants du client | Échanges entre serveurs (aucun utilisateur) | Non | Oui — reste sur le serveur |
Flux d'autorisation
Le flux standard pour les applications web avec un serveur backend. Le jeton d'accès et le secret du client ne touchent jamais le navigateur — l'échange de jeton se fait côté serveur. C'est tout le point.
Étape 1 : Rediriger l'utilisateur
Construisez une URL d'autorisation et redirigez le navigateur vers elle :
GET https://accounts.example.com/oauth/authorize
?response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https://yourapp.com/callback
&scope=openid+profile+email
&state=RANDOM_CSRF_TOKEN
Le state la valeur est votre défense CSRF pour la redirection. Générez une chaîne aléatoire fraîche par flux, stockez-la dans la session, et vérifiez-la lorsque l'utilisateur revient. Si vous omettez ce contrôle, un attaquant peut conduire les utilisateurs à travers un flux en utilisant son propre code d'autorisation — en liant silencieusement l'identité de l'utilisateur à celle de l'attaquant.
Étape 2 : Gérer le rappel
L'authentificateur redirige le serveur vers votre redirect_uri avec un code à durée limitée :
GET https://yourapp.com/callback?code=AUTH_CODE&state=SAME_STATE_YOU_SENT
Vérifier state correspond à ce que vous avez stocké. Échangez ensuite le code côté serveur.
Étape 3 : Échanger le code pour des jetons (seulement côté serveur)
POST https://accounts.example.com/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=AUTH_CODE
&redirect_uri=https://yourapp.com/callback
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
La réponse :
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "def50200a12b3c...",
"scope": "openid profile email"
}
Conservez les deux jetons côté serveur. Lorsque access_token expire (vérifiez expires_in), utilisez le refresh_token pour obtenir un nouveau jeton sans faire rediriger l'utilisateur.
PKCE — Pour les clients qui ne peuvent pas garder des secrets
Une application SPA ou mobile n'a pas de lieu sûr pour un client_secret. Quiconque peut ouvrir DevTools et le trouver dans votre bundle JS. Quiconque peut décompiler votre APK. Le PKCE (Proof Key for Code Exchange, prononcé « pixy ») résout cela avec un défi cryptographique unique — aucun secret partagé n'est nécessaire.
Le flux est identique au code d'autorisation avec deux ajouts : un code_verifier (chaîne aléatoire que vous gérez) et un code_challenge (hachage SHA-256 du vérificateur, encodé en base64url). Vous envoyez le défi en amont, puis vous prouvez que vous détenez le vérificateur au moment de l'échange.
Étape 1 : Générer le vérificateur et le défi
function generateCodeVerifier() {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return base64url(array);
}
async function generateCodeChallenge(verifier) {
const data = new TextEncoder().encode(verifier);
const digest = await crypto.subtle.digest('SHA-256', data);
return base64url(new Uint8Array(digest));
}
function base64url(buffer) {
return btoa(String.fromCharCode(...buffer))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
// Usage
const codeVerifier = generateCodeVerifier();
const codeChallenge = await generateCodeChallenge(codeVerifier);
// Store codeVerifier in memory — NOT localStorage
Stockez le code_verifier en mémoire — une variable de portée de module, pas localStorage. Vous l'envoyez au moment de l'échange de jeton.
Étape 2 : Demande d'autorisation — ajouter le défi
GET https://accounts.example.com/oauth/authorize
?response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https://yourapp.com/callback
&scope=openid+profile
&state=RANDOM_CSRF_TOKEN
&code_challenge=BASE64URL_SHA256_OF_VERIFIER
&code_challenge_method=S256
Étape 3 : Échange de jeton — le vérificateur au lieu du client_secret
POST https://accounts.example.com/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=AUTH_CODE
&redirect_uri=https://yourapp.com/callback
&client_id=YOUR_CLIENT_ID
&code_verifier=ORIGINAL_VERIFIER_YOU_GENERATED
L'authentificateur hachage le vérificateur et le vérifie contre le défi que vous avez envoyé à l'étape 2. Un attaquant qui a intercepté le code d'autorisation n'a aucune idée de ce que le vérificateur est — ils ne peuvent pas l'échanger.
À retenir : OAuth 2.1 (la modernisation en cours de OAuth 2.0) impose le PKCE pour tous les flux impliquant des redirections. Si vous écrivez du nouveau code, utilisez le PKCE, quel que soit le besoin actuel de votre fournisseur.
Identifiants du client — Aucun utilisateur, aucun problème
Les tâches de fond, les microservices appelant d'autres microservices, les tâches cron accédant à une API — aucune de ces situations ne implique un utilisateur. Le flux des identifiants du client est le bon choix : le service s'authentifie directement en utilisant son propre identifiant et son secret.
POST https://accounts.example.com/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&scope=api:read api:write
Réponse :
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 86400
}
Aucun jeton de rafraîchissement — quand il expire, demandez simplement un nouveau jeton. L'erreur commune : appeler le point d'entrée de jeton à chaque appel API. Stockez le jeton, vérifiez l'expiration avant chaque appel, et réexigez-le uniquement quand il est sur le point d'expirer. Un appel de jeton par jour (ou par heure, selon expires_in) au lieu d'un appel par appel :
let cachedToken = null;
let tokenExpiresAt = 0;
async function getAccessToken() {
// Refresh 30 seconds before actual expiry
if (cachedToken && Date.now() < tokenExpiresAt - 30_000) {
return cachedToken;
}
const res = await fetch('https://accounts.example.com/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET,
scope: 'api:read api:write',
}),
});
const data = await res.json();
cachedToken = data.access_token;
tokenExpiresAt = Date.now() + (data.expires_in * 1000);
return cachedToken;
}
Erreurs que les développeurs commettent réellement
Stockage des jetons dans localStorage
Toute vulnérabilité XSS — dans votre propre code, une dépendance, un script de gestion de tags — peut lire tout ce qui est stocké dans localStorage. Pour les SPAs : stockez le jeton d'accès en mémoire (une variable de portée de module qui disparaît à chaque rafraîchissement). Utilisez des cookies httpOnly pour les jetons de rafraîchissement lorsque vous avez un backend capable de les définir. JavaScript ne peut pas lire les cookies httpOnly.
Utilisation du flux implicite
Le flux implicite retourne les jetons directement dans le fragment de l'URL (#access_token=...). Ces jetons se retrouvent dans l'historique du navigateur, les journaux d'accès du serveur et les en-têtes Referer. Il a été déprécié dans RFC 9700. Il n'y a aucune raison d'utiliser le flux implicite pour du nouveau code. Utilisez le PKCE.
Omission de la validation de l'état
Sans state La validation sur le rappel, un attaquant peut créer une URL de redirection qui complète un flux OAuth en utilisant son propre code d'autorisation. Le résultat : l'identité de l'utilisateur est liée à celle de l'attaquant au fournisseur. Générez-le frais par flux, stockez-le dans la session, vérifiez-le au rappel.
Mise en place du client_secret dans le code frontal
Il n'existe pas de secret qui vive dans un navigateur. La minification ne le cache pas. L'obfuscation ne le protège pas. Si votre environnement est un navigateur ou une application mobile, vous avez un client public — utilisez le PKCE et omettez le client_secret entièrement. Ce n'est pas un contournement ; c'est la manière dont la spécification prévoit que les clients publics fonctionnent.
Manque de gestion proactive de l'expiration du jeton
Chaque jeton d'accès a une expires_in valeur. Si vous conservez un jeton jusqu'à ce qu'il échoue avec un 401 et que vous réauthentifiez, les utilisateurs rencontrent des erreurs mystérieuses. Vérifiez l'expiration avant chaque appel, actualisez proactivement (30 secondes avant l'expiration est un bon buffer), et gérez le cas rare où un jeton de rafraîchissement lui-même est expiré.
Inspection des jetons pendant le travail
La plupart des fournisseurs OAuth émettent des JWT comme jetons d'accès. Le payload est encodé en base64url et lisible sans la clé privée — seulement la signature nécessite la clé pour la vérification. Lorsque vous déboguez un flux et souhaitez voir les déclarations, les portées ou l'expiration dans un jeton, collez-le dans le Décodeur JWT.
Si vous testez manuellement le PKCE et que vous devez vérifier ce que décode une chaîne encodée en base64url code_challenge , le Convertisseur base64 gère les variantes standard et URL-sécurisées.
Version courte
Une seule question détermine le bon flux : votre environnement a-t-il un lieu sécurisé pour garder un secret ?
- Serveur backend → Code d'autorisation ou Identifiants du client (le secret reste sur le serveur)
- Navigateur ou application mobile → Code d'autorisation + PKCE (aucun secret du tout)
- Aucun utilisateur impliqué → Identifiants du client
Le PKCE fonctionne pour tous les flux impliquant une redirection — il n'y a pas d'inconvénient à l'utiliser même si votre fournisseur ne l'exige pas encore. OAuth 2.1 l'impliquera.
Installez nos extensions
Ajoutez des outils IO à votre navigateur préféré pour un accès instantané et une recherche plus rapide
恵 Le Tableau de Bord Est Arrivé !
Tableau de Bord est une façon amusante de suivre vos jeux, toutes les données sont stockées dans votre navigateur. D'autres fonctionnalités arrivent bientôt !
Outils essentiels
Tout voir Nouveautés
Tout voirMise à jour: Notre dernier outil a été ajouté le 12 juin 2026
