Une app mobile authentifie un utilisateur auprès d'un fournisseur d'identité et transmet l'access token à votre backend, qui appelle le endpoint de profil du fournisseur, récupère une adresse e-mail et crée une session. Tous les tests passent. Cela permet aussi à toute autre app à laquelle l'utilisateur s'est connecté avec ce fournisseur de se connecter à votre app en se faisant passer pour lui avec son propre access token, car rien ne vérifie à quelle app le token a été émis.
OpenID Connect (OIDC) comble cette faille. Il ajoute un ID token à OAuth 2.0 : un JWT signé dans lequel le fournisseur indique qui est l'utilisateur, à quelle app le token est destiné et quand l'utilisateur s'est connecté.
Cet article dessine l'authorization code flow avec PKCE sous forme de diagramme de séquence et couvre ce qu'OIDC ajoute : le scope openid, nonce, la validation de l'ID token, la discovery, la rotation des clés, UserInfo et la déconnexion.
OAuth 2.0 et OpenID Connect
OAuth 2.0 concerne l'accès : un token pour appeler une API au nom de l'utilisateur. OpenID Connect concerne l'identité : qui s'est connecté.
| OAuth 2.0 | OpenID Connect | |
|---|---|---|
| Question à laquelle il répond | Cette app peut-elle appeler cette API ? | Qui est l'utilisateur, et quand s'est-il connecté ? |
| Token | Access token | ID token |
| Le token est destiné à | L'API | Votre app |
| Format du token | Non défini : opaque ou JWT | Un JWT signé |
| Comment le demander | Des scopes définis par l'API | scope inclut openid |
| Définit | Les grants et les endpoints | Les claims, UserInfo, la discovery, la déconnexion |
Sur le réseau, une connexion OIDC est une requête d'autorisation OAuth avec openid dans le scope, et la réponse de jetons contient un id_token à côté de l'access token. Le diagramme du flux OAuth 2.0 détaille la partie OAuth.
Le flux, étape par étape
OpenID Connect Core 1.0 appelle votre app la relying party (RP) et le serveur d'autorisation l'OpenID provider (OP). Ce qui passe par le navigateur, le canal avant, peut fuiter dans les URL, l'historique et les logs ; les appels de votre backend vers le fournisseur, le canal arrière, ne le peuvent pas. Les numéros correspondent au diagramme.
- Démarrage (1–3). L'utilisateur clique sur Sign in. Votre app stocke dans la session un nouveau
state, unnonceet uncode_verifierPKCE, puis redirige le navigateur vers le fournisseur. - Requête d'authentification (4). Le navigateur suit la redirection :
GET /authorize?response_type=code
&client_id=orders-web
&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
&scope=openid%20profile%20email
&state=7fJq2LbX9aQe
&nonce=n-0S6_WzA2Mj
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256 HTTP/1.1
Host: op.example.com
- Connexion et consentement (5). Le fournisseur authentifie l'utilisateur (mot de passe, passkey, MFA ou session existante) et demande son consentement. Votre app ne voit jamais les identifiants.
- Retour du code (6–7). Le fournisseur redirige vers le
redirect_urienregistré avec uncodede courte durée et le mêmestate, que votre app compare à celui de la session. - Requête de jetons (8–9). Votre backend envoie en POST le
code, leredirect_uriet lecode_verifieravec ses identifiants client. Le fournisseur vérifie le verifier par rapport au challenge et renvoie unid_token, unaccess_tokenet souvent unrefresh_token. - Validation (10). Votre app valide l'ID token, en ne récupérant les clés de signature que si celle qu'il désigne n'est pas en cache.
- UserInfo (11–12), facultatif. Seulement si l'ID token ne contient pas les claims dont vous avez besoin.
- Session (13). Votre app crée sa propre session et pose un cookie.
Ce que protègent state, nonce et PKCE
| Valeur | Circule dans | Vérifiée par | Empêche |
|---|---|---|---|
state |
L'étape 4 et la redirection de retour | Votre app | Une réponse de connexion que l'utilisateur n'a jamais lancée (CSRF) |
nonce |
L'étape 4, puis dans l'ID token | Votre app | Le rejeu de l'ID token, et l'injection de code pour les clients confidentiels |
code_verifier |
Son hash SHA-256 à l'étape 4, lui-même à l'étape 8 | Le fournisseur | L'échange d'un code volé |
Les bonnes pratiques de sécurité OAuth, RFC 9700, permettent à l'une de ces valeurs d'en remplacer une autre dans certains cas, mais chacune ne coûte qu'une valeur aléatoire, donc envoyez les trois. Les clients publics, comme les applications monopages et mobiles, doivent utiliser PKCE (RFC 7636) avec S256.
Dans l'ID token
L'ID token de l'étape 9, décodé :
{
"iss": "https://op.example.com",
"sub": "248289761001",
"aud": "orders-web",
"nonce": "n-0S6_WzA2Mj",
"iat": 1793736400,
"exp": 1793740000,
"auth_time": 1793736390
}
| Claim | Signification | Votre app |
|---|---|---|
iss |
Émetteur, une URL https | Doit être exactement égal à l'issuer découvert |
sub |
Identifiant de l'utilisateur, jamais réattribué chez l'émetteur, 255 caractères ASCII au maximum | Utilise iss plus sub comme clé de compte |
aud |
Audience, une chaîne ou un tableau | Doit y trouver son client_id |
exp, iat |
Expiration et date d'émission, en secondes Unix | Rejette les tokens expirés ou très anciens |
nonce |
La valeur envoyée à l'étape 4 | Doit correspondre à la session |
auth_time |
Quand l'utilisateur s'est réellement authentifié | La vérifie quand vous envoyez max_age |
acr, amr |
Niveau d'assurance et méthodes, comme pwd ou mfa |
Les vérifie avant les actions sensibles |
Core est explicite : seul iss plus sub identifie un utilisateur, car les adresses e-mail changent et peuvent être réattribuées.
Valider l'ID token
La section 3.1.3.7 de Core énumère les règles :
- Fixez l'algorithme (RS256 par défaut) au lieu de vous fier à l'en-tête
alg, et n'acceptez jamaisnone. - Vérifiez la signature avec la clé JWKS désignée par
kid. Core autorise un client en code flow à s'appuyer sur TLS à la place, puisque le token vient directement du token endpoint, mais vérifier coûte peu. - Contrôlez
isspar rapport à l'émetteur découvert, caractère pour caractère. - Contrôlez
audpour votreclient_id, et rejetez les audiences auxquelles vous ne faites pas confiance. - Contrôlez
expetiat, en tolérant de quelques secondes à quelques minutes de décalage d'horloge. - Contrôlez
noncepar rapport à la session, puis supprimez-le. - Contrôlez
auth_timeetacrsi vous les avez demandés.
Ne créez la session qu'ensuite. Avec la bibliothèque jose dans Node.js :
import { createRemoteJWKSet, jwtVerify } from 'jose'
// issuer and jwks_uri come from the discovery document.
// The key set is cached; an unknown kid triggers a refetch
// (at most once every 30 seconds by default).
const JWKS = createRemoteJWKSet(new URL(oidc.jwks_uri))
const { payload } = await jwtVerify(tokens.id_token, JWKS, {
issuer: oidc.issuer, // exact match
audience: CLIENT_ID, // must appear in aud
algorithms: ['RS256'], // never trust the header alone
clockTolerance: 60, // seconds of clock skew
maxTokenAge: 600, // rejects an old iat
})
if (payload.nonce !== session.nonce) throw new Error('nonce mismatch')
Discovery et rotation des clés
OpenID Connect Discovery 1.0 place les paramètres d'un fournisseur dans un seul document JSON, à l'URL de l'émetteur suivie de /.well-known/openid-configuration. Celui de Google, réduit aux champs utilisés par ce flux, au moment de la rédaction (novembre 2026) :
{
"issuer": "https://accounts.google.com",
"authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
"token_endpoint": "https://oauth2.googleapis.com/token",
"userinfo_endpoint": "https://openidconnect.googleapis.com/v1/userinfo",
"jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
"id_token_signing_alg_values_supported": ["RS256"],
"code_challenge_methods_supported": ["plain", "S256"]
}
L'issuer doit être identique à l'URL d'émetteur depuis laquelle vous l'avez récupéré et au iss de chaque ID token. Configurez vous-même l'émetteur attendu ; ne le prenez jamais dans un token que vous n'avez pas vérifié.
Les clés tournent via le jwks_uri : le fournisseur ajoute une nouvelle clé, signe avec elle et garde l'ancienne publiée pendant un temps (Core, section 10.1.1). Mettez l'ensemble en cache, respectez Cache-Control, récupérez-le de nouveau face à un kid inconnu et limitez le débit de ces récupérations. Le diagramme du flux d'authentification JWT couvre les mêmes mécanismes pour les access tokens.
UserInfo
UserInfo renvoie les claims correspondant aux scopes accordés (profile, email, address, phone) quand vous l'appelez avec l'access token. Sa réponse contient toujours sub, qui doit correspondre exactement au sub de l'ID token, sinon vous écartez la réponse.
Options de déconnexion
Trois spécifications OpenID finales couvrent la déconnexion :
| Spécification | Fonctionnement | Points d'attention |
|---|---|---|
| RP-Initiated Logout 1.0 | Votre app redirige vers l'end_session_endpoint du fournisseur avec id_token_hint |
Votre app doit aussi mettre fin à sa propre session |
| Front-Channel Logout 1.0 | Le fournisseur charge l'URL de déconnexion de chaque app dans une iframe | Le blocage des cookies tiers peut l'empêcher de fonctionner |
| Back-Channel Logout 1.0 | Le fournisseur envoie en POST un logout token signé à chaque app | Votre app doit retrouver et terminer la session côté serveur |
Core précise aussi que l'exp de l'ID token n'a aucun rapport avec la durée de la session.
Erreurs qui reviennent en revue
- Un access token comme preuve d'identité. La scène d'ouverture. Authentifiez les utilisateurs uniquement avec un ID token que votre backend a obtenu auprès du token endpoint et validé.
- Ignorer
audounonce. Toutes les apps enregistrées chez le même fournisseur reçoivent des ID tokens correctement signés avec le mêmeiss; seulaudindique qu'un token vous a été émis, et seulnoncele lie à cette connexion. - L'implicit flow.
response_type=id_token tokenplace les tokens dans le fragment de l'URL ; la RFC 9700 dit que les clients ne devraient pas utiliser de response types qui renvoient des access tokens dans la réponse d'autorisation. Utilisezcodeavec PKCE, y compris dans les applications monopages. - Des ID tokens envoyés aux API. Les API ne devraient accepter que les access tokens émis pour elles ; le diagramme d'architecture d'une API gateway montre où se situe habituellement ce contrôle.
Le diagramme du flux OpenID Connect
Contenu du diagramme
- User
- Browser
- Relying party (your app)
- OpenID provider
- all checks must pass
- claims missing from the ID token
- ID token: for your app (aud = client_id)
- Access token: for UserInfo and APIs
- 1. Click Sign in
- 2. GET /login
- 3. 302 to the provider's /authorize
- 4. GET /authorize: scope=openid, state, nonce, code_challenge
- 5. Log in (password, passkey, MFA) and consent
- 6. 302 to redirect_uri with code, state
- 7. GET /callback?code&state
- 8. POST /token: code, code_verifier, client auth
- 9. id_token, access_token
- 10. GET jwks_uri (when kid is not cached)
- 11. GET /userinfo, Bearer access_token
- 12. Claims; sub must match the ID token
- 13. 302 to the app, Set-Cookie: session
Comment le lire :
- Quatre participants : l'utilisateur, le navigateur, votre app (la relying party) et l'OpenID provider. Le temps s'écoule vers le bas.
- Les couleurs indiquent le canal : bleu pour le passage par le navigateur, turquoise de votre backend vers le fournisseur, violet pour les actions de l'utilisateur. Les flèches en pointillés sont des réponses et des redirections.
- Les étapes 3 et 4 portent
scope=openid,state,nonceet le challenge PKCE ; l'étape 8 porte le verifier. - Le fragment
criticalcontient la récupération des clés et les contrôles qui doivent réussir avant qu'une session existe. Le fragmentoptest l'appel à UserInfo. - La colonne de droite associe les champs de discovery aux étapes, liste les paramètres PKCE, décode un ID token et montre quel token est destiné à qui.
Dessiner clairement des diagrammes OpenID Connect
- Donnez au navigateur sa propre ligne de vie. La séparation entre canal avant et canal arrière est l'histoire de sécurité du flux.
- Écrivez sur les flèches les paramètres contrôlés :
state,nonce,code_challenge,code_verifier. - Détaillez la validation. « Valider le token » ne peut pas être relu ; « signature, iss, aud, exp, iat, nonce » le peut.
- Indiquez quel token va où, avec son audience. Beaucoup de bugs OIDC sont un token envoyé au mauvais destinataire.
- Un flux par diagramme. Dessinez séparément la connexion, le rafraîchissement et la déconnexion, avec des identifiants et des tokens fictifs.
L'exemple de diagramme de séquence couvre la notation ; le diagramme du flux SAML SSO montre le protocole XML que les clients en entreprise demandent encore.
Le construire dans Archboard
- Connectez-vous avec Google ou GitHub et créez un diagramme.
- Depuis le pack Séquence, ajoutez un Acteur pour l'utilisateur et trois nœuds Ligne de vie de même hauteur : Browser, Relying party (votre app) et OpenID provider.
- Tracez les 13 messages sous forme d'arêtes droites numérotées, de haut en bas. Mettez les réponses en pointillés et colorez différemment le canal avant et le canal arrière.
- Ajoutez un Fragment combiné du pack Séquence avec l'opérateur
criticalautour de la récupération des clés et des contrôles, et un second Fragment combiné avecoptautour de l'appel à UserInfo. - Ajoutez un Texte du pack Base à côté de la relying party pour les valeurs de session et les contrôles, ainsi qu'une légende des couleurs.
- Ajoutez un bloc Markdown du pack Base pour la discovery, PKCE et un ID token décodé, et deux nœuds Jeton du pack Sécurité pour l'ID token et l'access token.
L'exemple utilise 9 nœuds de diagramme et reste dans les limites de l'offre Free. Votre agent IA peut aussi le dessiner via MCP.
FAQ
Quelle est la différence entre OAuth 2.0 et OpenID Connect ?
OAuth 2.0 donne à une app un access token pour appeler une API. OpenID Connect ajoute l'authentification par-dessus : le scope openid, un ID token qui dit qui est l'utilisateur, et des endpoints standard de discovery et UserInfo.
Un ID token est-il identique à un access token ? Non. L'ID token est un JWT signé destiné à votre app, qui dit qui s'est connecté. L'access token est destiné aux API, y compris UserInfo. N'envoyez jamais d'ID tokens aux API et n'acceptez jamais d'access tokens comme preuve de connexion.
Ai-je besoin de PKCE si j'envoie déjà un nonce ? Utilisez les deux. La RFC 9700 exige PKCE pour les clients publics. Un client confidentiel peut s'appuyer sur le nonce avec des précautions supplémentaires, mais PKCE empêche l'échange d'un code volé, alors que le nonce ne détecte un code injecté qu'après la réponse de jetons.
Comment valider un ID token ?
Vérifiez la signature avec la clé JWKS correspondant à son kid, puis contrôlez que iss est égal à l'émetteur, que aud contient votre client ID, que exp n'est pas dépassé, que iat est récent et que nonce correspond à la session.
Qu'est-ce que /.well-known/openid-configuration ?
Le document de discovery OpenID Connect. Il liste l'émetteur, les endpoints, les algorithmes et le jwks_uri d'un fournisseur, pour que votre app puisse se configurer à partir d'une seule URL.