Aller au contenu
medium

OpenID Connect : l'authentification moderne (SSO)

14 min de lecture

OpenID Connect (OIDC) ajoute l’identité à OAuth 2.0. Là où OAuth répond “cette app peut accéder à l’API”, OIDC répond “cet utilisateur est alice@exemple.com”. C’est le standard derrière tous les boutons “Se connecter avec…” et la base du SSO (Single Sign-On) moderne. Un seul login, accès à toutes vos applications.

Ce guide vous explique OpenID Connect (OIDC) — le standard pour l’authentification moderne. À la fin, vous saurez :

  • Comprendre ce qu’OIDC ajoute à OAuth 2.0 (spoiler : l’identité)
  • Décoder un ID Token et comprendre ses claims
  • Valider correctement un JWT (signature, issuer, audience, expiration)
  • Configurer une application avec Discovery et JWKS

Prérequis : avoir lu OAuth 2.x.

OAuth 2.0 vous dit : “Cette application a le droit d’accéder à ces données.”

OIDC vous dit : “Voici qui est l’utilisateur connecté.”

Terme OAuth 2.0Équivalent OIDC
Authorization ServerOpenID Provider (OP)
ClientRelying Party (RP)
ID Token (nouveau)
UserInfo Endpoint (nouveau)

L’ID Token est un JWT (JSON Web Token) qui contient l’identité de l’utilisateur authentifié.

Un JWT se compose de 3 parties séparées par des points :

header.payload.signature

Chaque partie est encodée en base64url.

Header :

{
"alg": "RS256",
"typ": "JWT",
"kid": "key-2024-02"
}

Payload (les claims) :

{
"iss": "https://auth.example.com",
"sub": "user-123",
"aud": "my-app-client-id",
"exp": 1700000000,
"iat": 1699996400,
"nonce": "abc123xyz",
"email": "alice@example.com",
"name": "Alice Martin",
"email_verified": true
}

Signature : permet de vérifier que le token n’a pas été modifié.

ClaimDescriptionObligatoire
issIssuer — URL de l’OP qui a émis le token
subSubject — identifiant unique de l’utilisateur
audAudience — client_id de l’application destinataire
expExpiration — timestamp UNIX
iatIssued At — timestamp de création
nonceAnti-replay — valeur envoyée à l’autorisation⚠️ Recommandé
auth_timeMoment de l’authentificationOptionnel
acrAuthentication Context Class ReferenceOptionnel
ClaimDescription
nameNom complet
given_namePrénom
family_nameNom de famille
emailAdresse email
email_verifiedEmail vérifié (booléen)
pictureURL de la photo de profil
localeLangue préférée
  1. Vérifier la signature

    Récupérez les clés publiques via JWKS et vérifiez la signature. Utilisez le kid (Key ID) du header pour trouver la bonne clé.

  2. Vérifier l’issuer (iss)

    Doit correspondre exactement à votre OpenID Provider attendu. Une différence = token d’un autre IdP.

  3. Vérifier l’audience (aud)

    Doit contenir votre client_id. Un token valide pour une autre app n’est pas valide pour vous.

  4. Vérifier l’expiration (exp)

    Le token ne doit pas être expiré. Comparez avec l’heure actuelle (attention aux fuseaux horaires).

  5. Vérifier le nonce

    Si vous avez envoyé un nonce à l’autorisation, vérifiez qu’il correspond. Protection contre les attaques de replay.

  6. Vérifier l’algorithme (alg)

    Refusez alg: none — signature désactivée. N’acceptez que les algorithmes attendus (RS256, ES256…).

import jwt from 'jsonwebtoken';
import jwksClient from 'jwks-rsa';
const client = jwksClient({
jwksUri: 'https://auth.example.com/.well-known/jwks.json',
cache: true,
cacheMaxAge: 600000, // 10 minutes
});
async function validateIdToken(token) {
// 1. Décoder le header pour obtenir le kid
const decoded = jwt.decode(token, { complete: true });
if (!decoded) throw new Error('Invalid token format');
// 2. Récupérer la clé publique
const key = await client.getSigningKey(decoded.header.kid);
const publicKey = key.getPublicKey();
// 3. Vérifier le token complet
const verified = jwt.verify(token, publicKey, {
issuer: 'https://auth.example.com',
audience: 'my-app-client-id',
algorithms: ['RS256', 'ES256'], // Whitelist explicite
});
// 4. Vérifier le nonce (si utilisé)
if (verified.nonce !== expectedNonce) {
throw new Error('Nonce mismatch');
}
return verified;
}

Ces deux tokens ont des usages différents. Ne les confondez pas.

AspectID TokenAccess Token
Consommé parLe client (Relying Party)L’API (Resource Server)
ContenuIdentité de l’utilisateurPermissions (scopes)
Question”Qui est connecté ?""Quels accès sont autorisés ?”
FormatToujours JWTJWT ou opaque
Durée de vieCourte (minutes)Courte (minutes)
Envoyé à l’API❌ Non✅ Oui

Les OpenID Providers publient leur configuration à une URL standardisée :

https://auth.example.com/.well-known/openid-configuration
{
"issuer": "https://auth.example.com",
"authorization_endpoint": "https://auth.example.com/authorize",
"token_endpoint": "https://auth.example.com/token",
"userinfo_endpoint": "https://auth.example.com/userinfo",
"jwks_uri": "https://auth.example.com/.well-known/jwks.json",
"scopes_supported": ["openid", "profile", "email", "offline_access"],
"response_types_supported": ["code", "id_token", "token"],
"id_token_signing_alg_values_supported": ["RS256", "ES256"],
"claims_supported": ["sub", "name", "email", "email_verified"]
}
  • Pas de configuration manuelle : l’application découvre les endpoints automatiquement
  • Rotation transparente : les URLs peuvent changer sans casser les clients
  • Validation de l’issuer : vérifiez que l’issuer Discovery correspond à celui attendu

Le JWKS (JSON Web Key Set) contient les clés publiques pour vérifier les signatures des tokens.

GET https://auth.example.com/.well-known/jwks.json
{
"keys": [
{
"kid": "key-2024-02",
"kty": "RSA",
"alg": "RS256",
"use": "sig",
"n": "0vx7agoebG...",
"e": "AQAB"
},
{
"kid": "key-2024-01",
"kty": "RSA",
"alg": "RS256",
"use": "sig",
"n": "abc123...",
"e": "AQAB"
}
]
}

Les clés de signature changent régulièrement (sécurité, compromission). Votre application doit :

  1. Cacher les clés JWKS avec un TTL raisonnable (5-15 minutes)

  2. Rafraîchir si un kid inconnu apparaît dans un token

  3. Valider que le nouveau kid provient bien du bon endpoint JWKS

Le UserInfo endpoint retourne des informations supplémentaires sur l’utilisateur authentifié.

Fenêtre de terminal
curl -H "Authorization: Bearer <access_token>" \
https://auth.example.com/userinfo

Réponse :

{
"sub": "user-123",
"name": "Alice Martin",
"email": "alice@example.com",
"email_verified": true,
"picture": "https://example.com/photos/alice.jpg"
}
AspectID TokenUserInfo
DisponibleAu moment du loginÀ tout moment avec un access token valide
FormatJWT signéJSON simple
FraîcheurFigé au moment de l’émissionPeut refléter des changements récents
UsageAuthentification initialeMise à jour du profil
SessionGérée parDurée
Session IdPL’OpenID ProviderLongue (heures/jours)
Session applicationVotre applicationConfigurable

Ces sessions sont indépendantes. La fin de l’une n’implique pas automatiquement la fin de l’autre.

Si l’utilisateur a déjà une session active sur l’IdP :

  1. Votre app redirige vers l’IdP
  2. L’IdP reconnaît l’utilisateur (session existante)
  3. L’IdP redirige immédiatement vers votre app avec les tokens
  4. Pas de login demandé

Pour déconnecter l’utilisateur de toutes les applications :

  1. L’application appelle le end_session_endpoint de l’IdP
  2. L’IdP invalide sa session
  3. L’IdP notifie les autres applications (front-channel ou back-channel logout)
// Logout OIDC
const logoutUrl = new URL('https://auth.example.com/logout');
logoutUrl.searchParams.set('id_token_hint', idToken);
logoutUrl.searchParams.set('post_logout_redirect_uri', 'https://myapp.com/logged-out');
window.location.href = logoutUrl.toString();

Avec des tokens JWT, vous pouvez avoir des sessions stateless :

  • Pas de session serveur à maintenir
  • Le token contient toutes les informations
  • Problème : révocation difficile (attendre l’expiration)

Mitigation : tokens courts (15-30 min) + refresh tokens révocables côté serveur.

ScopeClaims retournés
openidsub (obligatoire pour OIDC)
profilename, family_name, given_name, picture, locale, etc.
emailemail, email_verified
addressaddress (objet structuré)
phonephone_number, phone_number_verified
offline_accessObtenir un refresh token
  1. L’utilisateur clique “Se connecter”

    L’application génère un state, un nonce, et un code_verifier (PKCE).

  2. Redirection vers l’IdP

    GET https://auth.example.com/authorize?
    response_type=code&
    client_id=my-app&
    redirect_uri=https://myapp.com/callback&
    scope=openid profile email&
    state=abc123&
    nonce=xyz789&
    code_challenge=SHA256(code_verifier)&
    code_challenge_method=S256
  3. Authentification sur l’IdP

    L’utilisateur entre ses credentials (et MFA si configuré).

  4. Consentement

    L’utilisateur accepte les scopes demandés (ou les a déjà acceptés).

  5. Retour avec le code

    GET https://myapp.com/callback?
    code=AUTH_CODE&
    state=abc123
  6. Échange du code contre les tokens

    Fenêtre de terminal
    POST https://auth.example.com/token
    Content-Type: application/x-www-form-urlencoded
    grant_type=authorization_code&
    code=AUTH_CODE&
    redirect_uri=https://myapp.com/callback&
    client_id=my-app&
    code_verifier=ORIGINAL_VERIFIER
  7. Réception des tokens

    {
    "access_token": "eyJhbGciOiJSUzI1Ni...",
    "id_token": "eyJhbGciOiJSUzI1Ni...",
    "refresh_token": "dGhpcyBpcyBhIHJlZn...",
    "token_type": "Bearer",
    "expires_in": 3600
    }
  8. Validation de l’ID Token

    L’application valide signature, iss, aud, exp, nonce.

  9. Session établie

    L’application crée une session pour l’utilisateur.

ErreurConséquenceSolution
Pas de validation audToken d’une autre app acceptéToujours valider l’audience
Accepter alg: noneTokens forgés acceptésWhitelist d’algorithmes
Ignorer le nonceVulnérable au replayGénérer et valider un nonce
ID Token envoyé à l’APIMauvais usage du tokenUtiliser l’access token pour les APIs
Pas de cache JWKSLatence à chaque validationCache avec TTL de 10-15 min

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.