Les pubs vous déplaisent ? Aller Sans pub Auj.

Fluxes OAuth 2.0 Code d'autorisation, PKCE et identifiants du client

Mis à jour le

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.

Flux OAuth 2.0 : Code d'autorisation, PKCE et Identifiants du client 1
ANNONCE · Supprimer ?

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.

FluxQuand les utiliserEst-ce que l'utilisateur est impliqué ?A-t-il besoin d'un client_secret ?
Code d'autorisationApplication web avec un serveur backendOuiOui — reste sur le serveur
Code d'autorisation + PKCEApplication SPA, application mobile, tout client publicOuiNon
Identifiants du clientÉchanges entre serveurs (aucun utilisateur)NonOui — 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.

Envie d'une expérience sans pub ? Passez à la version sans pub

Installez nos extensions

Ajoutez des outils IO à votre navigateur préféré pour un accès instantané et une recherche plus rapide

Sur Extension Chrome Sur Extension de bord Sur Extension Firefox Sur Extension de l'opéra

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 !

ANNONCE · Supprimer ?
ANNONCE · Supprimer ?
ANNONCE · Supprimer ?

Coin des nouvelles avec points forts techniques

Impliquez-vous

Aidez-nous à continuer à fournir des outils gratuits et précieux

Offre-moi un café
ANNONCE · Supprimer ?