Sécurité et identité
OAuth 2.0 expliqué : rôles, grants, PKCE et bonnes pratiques actuelles
Intermédiaire8 min de lectureMis à jour
Cette page a été traduite de l'anglais avec l'aide de l'IA, puis vérifiée par rapport à l'original. Lire la version anglaise
OAuth 2.0 permet à une application d'agir au nom d'un utilisateur sans jamais voir son mot de passe, et presque toutes les erreurs viennent d'un malentendu sur ce qu'il délègue. Ce guide présente les rôles, les messages HTTP de l'authorization code flow avec PKCE, les autres grants à connaître, le fonctionnement des scopes et du consentement, et ce que les bonnes pratiques de sécurité actuelles retirent de la spécification d'origine.
Ce que vous allez apprendre
- Expliquer ce que délègue OAuth 2.0 et pourquoi il relève de l'autorisation et non de l'authentification
- Suivre l'authorization code flow avec PKCE, message par message
- Choisir le bon grant pour une application côté navigateur, une application mobile, un traitement backend ou un téléviseur
- Utiliser correctement scopes, consentement, refresh tokens, introspection et révocation
- Appliquer les règles de la RFC 9700 sur les redirect URIs, les grants obsolètes et les sender-constrained tokens
OAuth 2.0 répond à une question bien précise : comment une application peut-elle appeler une API en votre nom sans que vous lui confiiez votre mot de passe ? Avant OAuth, la réponse honnête était que vous donniez vos identifiants à l'application en croisant les doigts : chaque intégration détenait alors les clés de tout votre compte, sans possibilité de révoquer l'une d'elles individuellement. OAuth remplace ce mécanisme par un token — restreint, à durée limitée, révocable — délivré après que vous avez approuvé une demande précise sur un site en qui vous avez déjà confiance.
Le framework est compact, mais souvent mal compris. C'est un framework d'autorisation, pas un protocole d'authentification ; la spécification ne dit volontairement rien de la manière dont l'utilisateur a prouvé son identité. Presque tous les problèmes sérieux rencontrés avec OAuth en production viennent soit de l'oubli de cette distinction, soit de l'implémentation d'un flow que l'écosystème a depuis abandonné. Ce guide couvre les rôles, les flows à utiliser en 2026, le comportement des tokens et les règles de la RFC 9700 qui remplacent une partie de la RFC 6749 d'origine.
Les quatre rôles
- Le resource owner est l'utilisateur à qui appartiennent les données — le plus souvent une personne, parfois une organisation.
- Le client est l'application qui veut y accéder. Il est confidentiel s'il peut garder un secret (une application web côté serveur) et public s'il ne le peut pas (une application mobile, une application exécutée dans le navigateur).
- L'authorization server authentifie le resource owner, recueille son consentement et émet les tokens. Il expose un authorization endpoint (front channel, navigateur) et un token endpoint (back channel, HTTPS direct).
- Le resource server est l'API qui accepte le token et sert les données.
Deux canaux de communication comptent tout au long du processus. Le front channel passe par le navigateur de l'utilisateur, au moyen de redirections : il est visible, journalisé et manipulable, donc rien de secret ne doit y transiter. Le back channel est un appel HTTPS direct de serveur à serveur, authentifié et privé. Concevoir un flow OAuth revient au fond à décider quelle valeur emprunte quel canal.
Authorization code flow avec PKCE, étape par étape
C'est le flow à utiliser aussi bien pour les applications web côté navigateur que pour les applications mobiles et les applications web rendues côté serveur. Proof Key for Code Exchange (RFC 7636) était au départ un correctif pour le mobile ; il est désormais obligatoire pour tous.
Le client génère d'abord une chaîne aléatoire à forte entropie, le code verifier, et en dérive un code challenge par hachage SHA-256 puis encodage base64url. Seul le challenge transite par le navigateur.
code_verifier = 43-128 chars of unreserved randomness, e.g. "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
code_challenge = BASE64URL( SHA256( code_verifier ) )
1. Requête d'autorisation. Le client redirige le navigateur vers l'authorization endpoint.
GET /authorize?response_type=code
&client_id=s6BhdRkqt3
&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
&scope=orders.read%20orders.write
&state=af0ifjsldkj
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256 HTTP/1.1
Host: auth.example.com
Le paramètre state est une valeur opaque que le client conserve dans sa session et vérifie au retour ; il lie la réponse à la requête et neutralise les attaques par cross-site request forgery sur l'endpoint de redirection.
2. Authentification et consentement. Le serveur d'autorisation authentifie l'utilisateur comme il l'entend — mot de passe plus second facteur, passkey, session existante — puis affiche un écran de consentement listant les scopes demandés. Le client n'intervient à aucun moment dans cette étape.
3. Redirection de retour avec un code.
HTTP/1.1 302 Found
Location: https://app.example.com/callback?code=SplxlOBeZQQYbYS6WxSbIA&state=af0ifjsldkj
L'authorization code est à usage unique, de courte durée (de quelques secondes à deux minutes) et inutilisable à lui seul.
4. Requête de token sur le back channel. Le client prouve maintenant qu'il est bien à l'origine du flow en envoyant le verifier initial.
POST /token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
5. Réponse de token.
{
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjIwMjYtMDMifQ...",
"token_type": "Bearer",
"expires_in": 300,
"refresh_token": "8xLOxBtZp8",
"scope": "orders.read orders.write"
}
Le serveur d'autorisation recalcule SHA256(code_verifier) et le compare au challenge qu'il a stocké. Un attaquant qui aurait intercepté le code sur le front channel ne peut pas l'échanger, car le verifier n'a jamais quitté le client légitime.
6. Appel de l'API. L'access token voyage dans l'en-tête Authorization, tel que défini par la RFC 6750, et le resource server le valide avant toute autre chose.
GET /orders/1042 HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjIwMjYtMDMifQ...
La façon de mener cette validation — vérification de la signature, contrôle des claims, rotation des clés — fait l'objet du guide sécuriser des API REST avec JWT. Si vous devez inspecter un token pendant un débogage, un décodeur JWT côté client en affiche les claims sans l'envoyer nulle part.
Les autres grants, et ceux qui ont disparu
Client credentials sert aux appels de machine à machine, sans aucun utilisateur : un traitement nocturne, un service qui en appelle un autre. Le client s'authentifie et reçoit un token qui le représente lui-même.
POST /token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&scope=ledger.post
Il n'y a pas de refresh token ici — le client redemande simplement un token — et aucune logique d'autorisation propre à un utilisateur ne doit être associée à ce token, puisqu'il ne représente aucun utilisateur.
Le device authorization grant (RFC 8628) couvre les appareils aux capacités de saisie limitées : un téléviseur, une imprimante, un outil en ligne de commande. L'appareil demande un code, affiche un code utilisateur court et une URL, puis interroge périodiquement le token endpoint pendant que l'utilisateur termine le flow sur son téléphone ou son ordinateur portable.
POST /device_authorization HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
client_id=tv-app&scope=video.play
{
"device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS",
"user_code": "WDJB-MJHT",
"verification_uri": "https://auth.example.com/device",
"expires_in": 1800,
"interval": 5
}
Le refresh token grant échange un refresh token contre un nouvel access token sans interaction de l'utilisateur. Les clients publics doivent pratiquer la rotation des refresh tokens : chaque utilisation renvoie un nouveau refresh token et invalide l'ancien, et si un token déjà utilisé réapparaît, le serveur révoque toute la chaîne, car ce scénario signifie qu'une copie a été volée.
Deux grants de la spécification d'origine sont désormais interdits par la RFC 9700. L'implicit grant renvoyait l'access token directement dans le fragment de l'URL, d'où il fuyait dans l'historique du navigateur, les referrers et n'importe quel script de la page ; le code flow avec PKCE couvre le même cas d'usage en toute sécurité. Le resource owner password credentials grant obligeait le client à manipuler le mot de passe de l'utilisateur, ce qui ruine la raison d'être même du framework et empêche l'authentification multifacteur et le step-up. C'est cette consolidation des règles que le secteur désigne sous le nom d'OAuth 2.1.
Scopes, consentement et audience
Un scope est une étiquette à granularité grossière désignant une permission demandée par le client — orders.read, profile, payments.initiate. Le serveur d'autorisation décide quels scopes un client donné a le droit de demander, l'utilisateur y consent et le resource server les fait respecter. Trois mises en garde :
- Les scopes décrivent ce que le client peut tenter, pas ce que l'utilisateur a le droit de faire. Avec un token portant
orders.read, l'API doit encore vérifier que cet utilisateur peut lire cette commande. Omettre cette vérification est le bug de contrôle d'accès lié à OAuth le plus répandu. - Limitez le nombre de scopes et faites en sorte qu'ils aient du sens. Des centaines de scopes très fins produisent des écrans de consentement illisibles, et un consentement que personne ne lit n'en est pas un.
- Utilisez l'
audience(ou un resource indicator) pour qu'un token émis pour une API ne puisse pas être rejoué contre une autre. Un token accepté partout transforme la compromission d'un seul service en compromission totale.
Pour les clients first-party, les organisations se passent souvent de l'écran de consentement ; c'est un choix de politique qui appartient au serveur d'autorisation, pas quelque chose que le client peut présumer.
Durée de vie des tokens, introspection et révocation
Les access tokens doivent être de courte durée — des minutes, pas des jours — parce que ce sont des bearer credentials : quiconque en détient un peut s'en servir. Les refresh tokens ont une longue durée de vie : ils doivent donc être stockés avec soin et liés au client.
Les tokens existent sous deux formes. Un token autoporteur (en général un JWT signé) peut être validé hors ligne par tout resource server qui détient les clés publiques de l'émetteur : cela passe bien à l'échelle, mais la révocation n'est pas instantanée. Un token opaque est un identifiant aléatoire que le resource server doit aller résoudre : la révocation est immédiate, au prix d'un appel réseau à chaque requête ; l'introspection définie par la RFC 7662 décrit cette résolution.
POST /introspect HTTP/1.1
Host: auth.example.com
Authorization: Basic cmVzb3VyY2Utc2VydmVyOnNlY3JldA==
Content-Type: application/x-www-form-urlencoded
token=mF_9.B5f-4.1JqM
{ "active": true, "scope": "orders.read", "client_id": "s6BhdRkqt3", "sub": "u-88231", "exp": 1789012345 }
Un compromis pragmatique consiste à combiner des JWT de courte durée et la révocation du refresh token, en acceptant une fenêtre bornée pendant laquelle une session révoquée fonctionne encore. Lorsque la révocation instantanée est une exigence ferme — paiements, accès d'administration —, une API gateway peut réaliser l'introspection de manière centralisée et en mettre le résultat en cache pendant quelques secondes.
Des règles de sécurité non négociables
- Enregistrez des redirect URIs exactes et comparez-les par égalité stricte de chaînes. Les wildcards et la correspondance par préfixe sont précisément ce qui permet de rediriger des tokens vers des chemins contrôlés par un attaquant. Une open redirect n'importe où sur l'hôte enregistré réintroduit le même problème.
- Envoyez toujours PKCE, vérifiez toujours
state. Ils protègent contre des attaques différentes : PKCE lie le code au client,statelie la réponse à la session. - Ne mettez jamais de tokens dans une query string. Les URL finissent dans les journaux d'accès, les proxys et les en-têtes Referer.
- Liez les tokens à celui qui les présente lorsque le risque le justifie. La liaison à un certificat mutual TLS (RFC 8705) ou DPoP (RFC 9449) rend un token volé inutilisable sans la clé correspondante.
- Validez le paramètre
issde la réponse d'autorisation lorsque le client dialogue avec plusieurs serveurs d'autorisation, afin d'éviter les attaques de type mix-up. - N'utilisez pas un access token pour identifier l'utilisateur. Utilisez OpenID Connect et son ID token, émis à destination de votre client et validé par lui.
Côté implémentation, la plupart des frameworks font désormais ce qu'il faut par défaut : Spring Security envoie PKCE pour les clients publics comme confidentiels et vérifie state à votre place. N'écrivez le flow vous-même que si vous y êtes obligé, et suivez alors la spécification à la lettre.
Points clés à retenir
- OAuth 2.0 délègue l'accès à une API sans partager d'identifiants ; il ne dit volontairement rien de la façon dont l'utilisateur s'est authentifié.
- Les valeurs qui passent par le navigateur sont publiques ; seul le back channel peut transporter des secrets, et c'est pour cela que le code flow existe.
- Utilisez l'authorization code flow avec PKCE pour tout client interactif, client credentials pour les appels de machine à machine et le device grant pour les appareils aux capacités de saisie limitées.
- Les grants implicit et password sont supprimés par la RFC 9700 ; les refresh tokens des clients publics doivent faire l'objet d'une rotation et être révoqués en chaîne en cas de réutilisation.
- Les scopes limitent ce qu'un client peut tenter — l'API doit toujours vérifier les droits de l'utilisateur sur la ressource précise.
- Une correspondance exacte des redirect URIs,
state, des access tokens de courte durée et la restriction d'audience font d'une intégration qui fonctionne une intégration sûre.
Sources et lectures complémentaires
Questions fréquentes
- OAuth 2.0 est-il un protocole de connexion ?
- Non. C'est un framework d'autorisation déléguée : il produit un access token indiquant qu'un client peut appeler une API avec certains scopes, et ne dit rien de standard sur l'identité de l'utilisateur ni sur le moment où il s'est authentifié. Se servir d'un access token comme preuve de connexion est un anti-pattern bien connu, car ce token a été émis pour une API, pas pour votre application. OpenID Connect ajoute la couche d'identité qui répond à ces questions.
- Les clients confidentiels ont-ils encore besoin de PKCE ?
- Oui. La RFC 9700 exige PKCE pour tout échange d'authorization code, et pas seulement pour les clients publics. Un client secret prouve quelle application échange le code, mais PKCE lie en plus ce code à la session de navigateur précise qui a lancé le flow : c'est ce qui neutralise l'injection et l'interception de code lorsque plusieurs acteurs partagent l'environnement de redirection.
- Où une single-page application doit-elle conserver ses tokens ?
- Idéalement nulle part. Le pattern recommandé est un backend-for-frontend qui réalise l'échange du code côté serveur et y garde les tokens, le navigateur ne recevant qu'un cookie de session HttpOnly. Si la SPA doit malgré tout détenir un token, gardez-le en mémoire plutôt que dans localStorage, avec des durées de vie courtes et la rotation des refresh tokens, en sachant que toute injection de script dans la page peut l'exfiltrer.
- Qu'est-ce qui a remplacé les grants implicit et password ?
- Les bonnes pratiques actuelles les suppriment tous les deux. Les applications côté navigateur utilisent l'authorization code flow avec PKCE, qui ne place jamais de token dans un fragment d'URL et ne l'expose donc jamais à l'historique du navigateur ni aux referrers. Les applications first-party qui utilisaient le resource owner password credentials grant doivent plutôt rediriger vers le serveur d'autorisation, pour que l'authentification multifacteur, le step-up et le consentement restent centralisés.