OAuth 2.0 et OpenID Connect
Comprendre les rôles et les flux d'OAuth 2.0, puis ce qu'OpenID Connect ajoute pour authentifier l'utilisateur (ID token, claims, discovery, JWKS).
Sur cette page
OAuth 2.0 et OpenID Connect (OIDC) sont les deux protocoles que vous croiserez le plus souvent avec Keycloak. OAuth 2.0 permet à une application d’obtenir un droit d’accès à une API. OIDC ajoute une couche d’identité : il dit à l’application qui est l’utilisateur. Ce cours présente les deux, dans cet ordre.
Les quatre rôles d’OAuth 2.0
La RFC 6749 définit quatre rôles.
| Rôle | Ce qu’il fait | Exemple |
|---|---|---|
| Resource owner | Possède les données, accorde l’accès | L’utilisateur |
| Client | Application qui veut accéder aux données | Le portail RH |
| Authorization server | Authentifie et délivre les jetons | Keycloak |
| Resource server | API qui protège les données | L’API de gestion des congés |
Le client ne reçoit jamais le mot de passe de l’utilisateur. Il reçoit un access token, un jeton à durée de vie courte qu’il présente à l’API dans l’en-tête Authorization: Bearer .... Il peut aussi recevoir un refresh token, plus durable, qui sert uniquement à demander un nouvel access token au serveur d’autorisation sans solliciter l’utilisateur.
Clients publics et confidentiels
OAuth 2.0 distingue deux types de clients selon leur capacité à garder un secret.
- Un client confidentiel s’exécute sur un serveur. Il détient un secret (ou une clé privée) et s’authentifie auprès du serveur d’autorisation. Exemple : une application Java côté serveur.
- Un client public s’exécute chez l’utilisateur : application JavaScript dans le navigateur, application mobile. Tout ce qu’il contient peut être lu. Il n’a donc pas de secret.
Ce choix conditionne les flux possibles et les protections à mettre en place.
Le flux authorization code avec PKCE
C’est le flux de référence pour connecter un utilisateur, que le client soit public ou confidentiel. PKCE (Proof Key for Code Exchange, RFC 7636) l’a renforcé.
La requête de l’étape 2 ressemble à ceci :
GET /realms/demo/protocol/openid-connect/auth?response_type=code
&client_id=portail-rh
&redirect_uri=https%3A%2F%2Fportail.exemple.fr%2Fcallback
&scope=openid%20profile%20email
&state=af0ifjsldkj
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256 HTTP/1.1
Host: idp.exemple.fr
Puis l’échange du code à l’étape 5, fait par le client hors du navigateur :
POST /realms/demo/protocol/openid-connect/token HTTP/1.1
Host: idp.exemple.fr
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fportail.exemple.fr%2Fcallback
&client_id=portail-rh
&code_verifier=dBjftJeZ4CVP-mJ92K9dTZ6aMyvBhdV1dTkqEC9pV7c
Le paramètre state protège contre la falsification de requête (CSRF). Le code_verifier prouve que celui qui échange le code est bien celui qui a lancé le flux. Un client confidentiel ajoute en plus son authentification (secret ou assertion signée).
Le flux client credentials
Quand aucun utilisateur n’est en jeu, un programme demande un jeton en son propre nom. C’est le cas d’un traitement de nuit qui appelle une API. Seul un client confidentiel peut l’utiliser.
POST /realms/demo/protocol/openid-connect/token HTTP/1.1
Host: idp.exemple.fr
Content-Type: application/x-www-form-urlencoded
Authorization: Basic YmF0Y2gtcGFpZTpzZWNyZXQ=
grant_type=client_credentials&scope=paie.lecture
Aucun ID token n’est émis : il n’y a pas d’utilisateur à identifier.
Les scopes
Un scope est une permission demandée par le client, sous forme d’une chaîne de caractères : paie.lecture, profile, email. Le serveur d’autorisation peut accorder tout ou partie des scopes demandés. L’API vérifie ensuite que le jeton présenté contient le scope nécessaire. Les scopes expriment ce que le client a le droit de faire au nom de l’utilisateur, pas l’ensemble des droits de l’utilisateur.
Les flux à proscrire
La RFC 9700 (janvier 2025) rassemble les bonnes pratiques de sécurité OAuth 2.0. Deux flux de la RFC 6749 y sont écartés.
| Flux | Problème | Position de la RFC 9700 |
|---|---|---|
| Implicit | L’access token transite dans l’URL du navigateur : historique, journaux, fuite par le Referer | Ne devrait pas être utilisé (SHOULD NOT) ; utiliser authorization code |
| Resource owner password credentials | Le client voit le mot de passe ; incompatible avec le MFA et la fédération | Ne doit pas être utilisé (MUST NOT) |
La RFC 9700 recommande aussi PKCE pour tous les clients, la comparaison exacte des redirect_uri enregistrées et la limitation des droits des access tokens.
OpenID Connect : la couche d’identité
OAuth 2.0 ne dit rien de l’utilisateur. OIDC ajoute :
- le scope
openid, qui déclenche le comportement OIDC ; - l’ID token, un JWT destiné au client qui décrit l’authentification ;
- des claims standard (
sub,name,email, etc.) et des scopes pour les demander (profile,email,address,phone) ; - l’endpoint userinfo, qui renvoie les claims de l’utilisateur sur présentation d’un access token ;
- la discovery, un document JSON qui décrit le serveur.
Anatomie d’un ID token
Un JWT est composé de trois parties encodées en Base64URL et séparées par des points : en-tête, contenu, signature. Voici un ID token décodé.
{
"alg": "RS256",
"typ": "JWT",
"kid": "x7Fq2kVn9pLr3sT8uW1yZ4aB6cD0eG5h"
}
{
"iss": "https://idp.exemple.fr/realms/demo",
"sub": "8f3c2a10-5d4e-4b7a-9c1f-2e6d7a8b9c0d",
"aud": "portail-rh",
"exp": 1762354800,
"iat": 1762354500,
"auth_time": 1762354490,
"nonce": "n-0S6_WzA2Mj",
"acr": "1",
"azp": "portail-rh",
"preferred_username": "cmartin",
"name": "Claire Martin",
"email": "claire.martin@exemple.fr",
"email_verified": true
}
Le client doit vérifier la signature avec la clé publique désignée par kid, puis que iss est l’émetteur attendu, que aud contient son propre client_id, que exp n’est pas dépassé et que nonce correspond à la valeur envoyée dans la requête d’autorisation. auth_time et acr indiquent quand et avec quel niveau l’utilisateur s’est authentifié ; le cours sur le MFA y revient.
Discovery et JWKS
Chaque serveur OIDC publie un document de configuration à une adresse fixe : l’émetteur suivi de /.well-known/openid-configuration (OpenID Connect Discovery 1.0). On y trouve les adresses des endpoints, les flux et algorithmes supportés, et jwks_uri.
Le JWKS (JSON Web Key Set) est la liste des clés publiques de signature du serveur :
{
"keys": [
{
"kid": "x7Fq2kVn9pLr3sT8uW1yZ4aB6cD0eG5h",
"kty": "RSA",
"alg": "RS256",
"use": "sig",
"n": "0vx7agoebGcQSuu...",
"e": "AQAB"
}
]
}
Grâce à la discovery et au JWKS, une bibliothèque cliente se configure avec la seule adresse de l’émetteur. Lors d’une rotation de clés, le serveur publie la nouvelle clé dans le JWKS et les clients la récupèrent sans intervention.
Lire le document de discovery de Keycloak
10 min
Installer le lab- Démarrez l’environnement du dossier
keycloak-academy-lab/et vérifiez que Keycloak répond sur http://localhost:8080. - Récupérez le document de discovery du realm
masteret affichez quelques champs.
curl -s http://localhost:8080/realms/master/.well-known/openid-configuration \
| jq '{issuer, authorization_endpoint, token_endpoint, userinfo_endpoint, jwks_uri}'- Vérifiez que
issuervauthttp://localhost:8080/realms/masteret que les autres adresses commencent par cet émetteur. - Repérez les flux annoncés dans
grant_types_supportedet les méthodes PKCE danscode_challenge_methods_supported.
curl -s http://localhost:8080/realms/master/.well-known/openid-configuration \
| jq '.grant_types_supported, .code_challenge_methods_supported'- Ouvrez l’adresse
jwks_uriet notez lekidet l’algde la clé dontusevautsig.
Si jq n’est pas installé, ouvrez simplement l’adresse dans votre navigateur : les navigateurs récents affichent le JSON de façon lisible.
Vérifier ce que vous avez retenu
4 questions
-
Une application monopage (SPA) en JavaScript doit connecter des utilisateurs. Quel flux faut-il retenir selon les bonnes pratiques actuelles ?
RFC 9700 déconseille implicit et interdit password. Une SPA ne peut pas garder de secret : c'est un client public, protégé par PKCE.
-
Quel jeton une application doit-elle valider pour savoir qui vient de se connecter ?
L'ID token est destiné au client et sert à l'authentification. L'access token est destiné à l'API : son format n'est pas garanti par OAuth 2.0 et le client ne doit pas s'y fier pour identifier l'utilisateur.
-
Que protège PKCE dans le flux authorization code ?
Le client envoie un hash (code_challenge) au départ et révèle le secret d'origine (code_verifier) à l'échange. Un attaquant qui vole le code ne connaît pas ce secret.
-
Comment une application obtient-elle la clé publique qui permet de vérifier la signature d'un JWT émis par le serveur ?
Le document .well-known/openid-configuration annonce jwks_uri. L'application y récupère les clés publiques et choisit celle dont le kid correspond à l'en-tête du jeton.