OWASP & AppSec

OpenID Connect expliqué : flows, JWT, PKCE, sécurité 2026

OpenID Connect expliqué : OAuth 2.0 vs OIDC, flows, Authorization Code + PKCE, ID Token JWT, scopes, attaques, Workload Identity Federation CI/CD.

Naim Aouaichia
12 min de lecture
  • OpenID Connect
  • OAuth 2.0
  • Authentification
  • JWT
  • PKCE
  • Identity
  • Secure coding
  • API Security

OpenID Connect (OIDC) est une couche d'authentification standardisée en 2014 par la OpenID Foundation, construite au-dessus du framework d'autorisation OAuth 2.0 (RFC 6749, 2012). Sa fonction : permettre à une application (Relying Party) de vérifier l'identité d'un utilisateur authentifié par un OpenID Provider (Google, Microsoft, Okta, Auth0, Keycloak, Entra ID) via un ID Token au format JWT. Différence essentielle avec OAuth 2.0 : OAuth gère l'autorisation (accès à des ressources au nom de l'utilisateur), OIDC gère l'authentification (qui est l'utilisateur). En 2026, OIDC est le protocole standard pour le SSO d'entreprise, l'authentification des applications web modernes, et le Workload Identity Federation dans les pipelines CI/CD (remplacement des clés statiques cloud). Le flow recommandé est Authorization Code avec PKCE (RFC 7636) pour tous les clients publics, les flows Implicit et ROPC étant officiellement dépréciés par OAuth 2.1 (2024). Cet article détaille les définitions, les 5 flows, la structure des tokens, les attaques courantes (JWT alg:none, open redirect, token substitution), et les bonnes pratiques d'implémentation.

OAuth 2.0 vs OpenID Connect : la confusion à éliminer

OAuth 2.0 : framework d'autorisation

OAuth 2.0 permet à une application d'obtenir un accès délégué à des ressources appartenant à un utilisateur, sans partager son mot de passe. Exemple classique : une application comptable demande accès à vos transactions bancaires.

Scénario OAuth 2.0 :
  Utilisateur  → autorise App Comptable
  App Comptable → reçoit Access Token → appelle API bancaire
  API Bancaire → vérifie Access Token → retourne données

OAuth ne dit rien sur qui est l'utilisateur. Il dit seulement : « ce client a le droit d'accéder à cette ressource avec ce scope ».

OIDC : couche d'authentification

OpenID Connect ajoute un ID Token qui décrit l'utilisateur authentifié.

Scénario OIDC :
  Utilisateur  → se connecte via Google sur App MonSite
  Google → émet Access Token + ID Token au client MonSite
  MonSite → lit l'ID Token (JWT) → connaît l'identité vérifiée

L'ID Token est un JWT qui contient des claims standardisés (sub, email, name, iss, aud, exp, nonce) signés par l'OpenID Provider.

Les 3 rôles OIDC

OpenID Provider (OP)
  aka Authorization Server, Identity Provider (IdP)
  Exemple : Google, Microsoft Entra ID, Okta, Auth0, Keycloak
  Rôle : authentifier l'utilisateur, émettre tokens
 
Relying Party (RP)
  aka Client Application
  Exemple : votre application web, mobile, SPA
  Rôle : consommer l'ID Token pour connaître l'utilisateur
 
End User
  L'utilisateur final qui s'authentifie

Les 5 flows OIDC

1. Authorization Code + PKCE - flow recommandé 2026

Standard pour les clients publics (SPA, mobile, desktop) et fortement recommandé aussi pour clients confidentiels web server-side.

Étape 1 - Client génère PKCE :
  code_verifier = random 43-128 chars
  code_challenge = BASE64URL(SHA256(code_verifier))
 
Étape 2 - Redirection authorization :
  GET https://op.example/authorize
    ?response_type=code
    &client_id=xyz
    &redirect_uri=https://app.example/callback
    &scope=openid profile email
    &state=<csrf_random>
    &nonce=<replay_protection_random>
    &code_challenge=<hash>
    &code_challenge_method=S256
 
Étape 3 - Utilisateur s'authentifie chez OP
  Login + MFA éventuel
 
Étape 4 - OP redirige vers le client avec un code :
  GET https://app.example/callback?code=ABC123&state=<csrf_random>
 
Étape 5 - Client échange code contre tokens (backend ou SPA PKCE) :
  POST https://op.example/token
    grant_type=authorization_code
    code=ABC123
    redirect_uri=https://app.example/callback
    client_id=xyz
    code_verifier=<original_secret>
 
Étape 6 - OP valide code_verifier vs code_challenge, retourne :
  {
    "access_token": "...",
    "id_token": "eyJhbG...",
    "refresh_token": "...",
    "token_type": "Bearer",
    "expires_in": 3600
  }

2. Client Credentials - service-to-service

Utilisé quand deux services dialoguent sans utilisateur final. Exemple : microservice A appelle microservice B.

POST https://op.example/token
  grant_type=client_credentials
  client_id=service-a
  client_secret=...
 
Réponse :
  access_token + expires_in (pas d'ID Token car pas d'utilisateur)

3. Device Authorization - IoT, TV

Pour les appareils sans clavier (TV connectée, device IoT). L'utilisateur valide sur un autre device (smartphone) en saisissant un code.

Device → POST /device_authorization → reçoit user_code, device_code, verification_uri
TV affiche : « Allez sur https://op.example/device et entrez ABC-123 »
Utilisateur se connecte sur smartphone avec ce code
Device polle /token avec device_code jusqu'à obtention

4. Hybrid Flow

Combinaison Authorization Code + ID Token dans la réponse immédiate. Moins utilisé en 2026 car complexe. Utilisé dans certaines intégrations SSO enterprise legacy.

5. Implicit Flow (DÉPRÉCIÉ)

Flow historique pour SPA avant PKCE. Tokens retournés directement dans l'URL de redirection. Déprécié par OAuth 2.0 Security BCP et OAuth 2.1. Ne jamais utiliser en 2026 pour nouveaux déploiements.

Pourquoi déprécié :
  Token dans URL = fuite via Referer, logs serveur, extensions navigateur
  Pas de preuve de possession = replay possible
  Authorization Code + PKCE résout tous ces problèmes

Flow Resource Owner Password Credentials (DÉPRÉCIÉ)

L'utilisateur fournit son mot de passe directement au client (qui l'envoie au server pour obtenir un token). Déprécié par OAuth 2.1. Anti-pattern absolu : casse le principe même d'OAuth (pas de partage de mot de passe).

Structure d'un ID Token (JWT)

Un JWT est composé de trois parties séparées par des points : header.payload.signature.

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9
.
eyJpc3MiOiJodHRwczovL29wLmV4YW1wbGUiLCJzdWIiOiJ1c2VyXzEyMyIsImF1ZCI6ImNsaWVudF94eXoiLCJleHAiOjE3MzQ5MDAwMDAsImlhdCI6MTczNDg5NjQwMCwibm9uY2UiOiJhYmMxMjMiLCJlbWFpbCI6ImFsaWNlQGV4YW1wbGUuY29tIn0
.
signature_RSA256_base64url

Header décodé

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "123"
}

Payload décodé (claims)

{
  "iss": "https://op.example",
  "sub": "user_123",
  "aud": "client_xyz",
  "exp": 1734900000,
  "iat": 1734896400,
  "nonce": "abc123",
  "email": "alice@example.com",
  "email_verified": true,
  "name": "Alice Dupont"
}

Claims standardisés

ClaimSignificationValidation obligatoire
issIssuer (OpenID Provider URL)Oui (matcher config attendue)
subSubject (ID utilisateur stable)Oui (jamais changer entre sessions)
audAudience (client_id destinataire)Oui (doit contenir votre client_id)
expExpiration timestamp (Unix)Oui (vérifier non expiré)
iatIssued atRecommandé
nonceProtection replay (fourni par client)Oui (matcher envoyé)
auth_timeTimestamp d'authentificationOptionnel
acrAuthentication Context Class Reference (niveau)Optionnel
amrAuthentication Methods ReferencesOptionnel

Validation d'un ID Token : checklist

# Exemple Python avec PyJWT + cryptography
import jwt
import requests
 
# 1. Récupérer JWKS de l'OpenID Provider
JWKS_URL = "https://op.example/.well-known/jwks.json"
jwks_client = jwt.PyJWKClient(JWKS_URL)
 
def validate_id_token(id_token: str, expected_client_id: str, nonce_sent: str) -> dict:
    # 2. Obtenir la clé publique correspondant au kid du header
    signing_key = jwks_client.get_signing_key_from_jwt(id_token)
 
    # 3. Valider signature, algorithme, issuer, audience, expiration
    payload = jwt.decode(
        id_token,
        signing_key.key,
        algorithms=["RS256"],  # JAMAIS ["none"], jamais de mix HS256/RS256
        audience=expected_client_id,
        issuer="https://op.example",
        options={"require": ["exp", "iat", "iss", "aud", "sub"]},
    )
 
    # 4. Vérifier le nonce
    if payload.get("nonce") != nonce_sent:
        raise ValueError("nonce mismatch - possible replay attack")
 
    return payload

Scopes OIDC standards

openid         : obligatoire pour déclencher OIDC (sinon OAuth pur)
profile        : name, family_name, given_name, picture, updated_at
email          : email, email_verified
phone          : phone_number, phone_number_verified
address        : address (structured)
 
Scopes custom :
  Exemples : "read:invoices", "write:reports"
  Définis par chaque OpenID Provider, reçus dans l'Access Token

Attaques courantes et parades

Attaque 1 - JWT alg:none

Un attaquant modifie le header JWT pour mettre "alg": "none" et retire la signature. Si le validateur accepte none, il accepte tout token.

Parade :
  Toujours whitelister les algorithmes acceptés (RS256, ES256)
  Bannir explicitement "none"
  Utiliser des bibliothèques qui refusent "none" par défaut (PyJWT 2.0+)

Attaque 2 - Confusion HS256 / RS256

Si le validateur ne vérifie pas strictement l'algorithme, un attaquant signe un JWT avec HS256 en utilisant la clé publique RS256 comme secret HMAC.

Parade :
  Toujours passer explicitement algorithms=["RS256"]
  Ne jamais déduire l'algorithme du header uniquement

Attaque 3 - Open redirect via redirect_uri

Un attaquant manipule le paramètre redirect_uri pour recevoir le code d'autorisation sur son propre domaine.

Parade :
  Whitelister strictement les redirect_uri côté OP (exact match, pas regex)
  Ne pas accepter les wildcards sur les redirect_uri
  Valider côté client que le state correspond

Attaque 4 - CSRF sans state

Sans paramètre state, un attaquant peut forger une requête qui lie son compte à la session victime.

Parade :
  Toujours générer un state aléatoire et le valider au callback
  Random cryptographique, au moins 128 bits d'entropie
  Lier le state à la session utilisateur (cookie)

Attaque 5 - Replay d'ID Token sans nonce

Sans nonce, un ID Token intercepté peut être rejoué.

Parade :
  Toujours inclure un nonce aléatoire dans la requête authorize
  Valider qu'il est présent dans l'ID Token reçu
  Ne jamais réutiliser un nonce

Attaque 6 - Token substitution (ID Token vs Access Token)

Une API qui accepte un ID Token comme Access Token est vulnérable à la substitution.

Parade :
  L'ID Token a aud=client_id (pas l'API)
  L'Access Token a aud=resource_server (l'API)
  L'API valide explicitement aud et refuse les tokens avec mauvaise audience

Attaque 7 - SSRF via URI parameter

Certains paramètres OIDC (jwks_uri, logo_uri, request_uri) acceptent des URLs utilisateur qui peuvent être exploitées pour SSRF côté OP.

Parade :
  Whitelister les domaines acceptés côté OP
  Bloquer les IP privées et métadonnées cloud
  Utiliser les recommandations OWASP SSRF Cheat Sheet

OIDC dans CI/CD : Workload Identity Federation

Depuis 2022-2023, OIDC est massivement adopté pour remplacer les clés statiques cloud (AWS access keys, GCP service account JSON, Azure app secrets) dans les pipelines CI/CD.

Principe

Le runner CI/CD émet un JWT OIDC signé avec des claims sur le contexte (repository, branch, environment, actor). Le cloud provider configuré en trust avec le provider OIDC du CI échange ce JWT contre des credentials court-durée (1-2 h).

GitHub Actions → AWS

name: deploy-to-aws
on: [push]
permissions:
  id-token: write       # requis pour émettre le JWT OIDC
  contents: read
 
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Configure AWS credentials via OIDC
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789:role/github-actions-deploy
          aws-region: eu-west-3
      - run: aws s3 sync ./dist s3://my-bucket/

Côté AWS, configurer un Identity Provider pointant vers token.actions.githubusercontent.com et une IAM Role avec trust policy qui vérifie aud=sts.amazonaws.com et sub=repo:org/repo:ref:refs/heads/main.

Autres providers CI/CD avec OIDC natif

GitHub Actions              : ✓ natif depuis 2021
GitLab CI                   : ✓ natif depuis 15.7 (2022)
CircleCI                    : ✓ natif depuis 2022
Bitbucket Pipelines         : ✓ natif
Jenkins                     : ✓ via plugin OIDC
Terraform Cloud / HCP       : ✓ Workload Identity natif
 
Destinations supportées :
  AWS IAM Identity Provider
  GCP Workload Identity Federation
  Azure Federated Credentials
  HashiCorp Vault JWT/OIDC auth method
  Kubernetes ServiceAccount Projected Tokens

Bibliothèques et frameworks 2026

Côté client (Relying Party)

JavaScript/TypeScript :
  oidc-client-ts (successor oidc-client-js)
  openid-client (Node.js backend)
  NextAuth.js (Next.js)
  Auth.js (framework-agnostic)
 
Python :
  Authlib                    : complet et maintenu
  requests-oauthlib         : léger
  mozilla-django-oidc        : Django
 
Java :
  Nimbus OAuth 2.0 SDK       : référence
  Spring Security OAuth2     : intégration Spring
 
Go :
  golang.org/x/oauth2
  github.com/coreos/go-oidc
 
Ruby :
  omniauth-openid-connect
 
Rust :
  openidconnect-rs

Côté serveur (OpenID Provider self-hosted)

Keycloak (Red Hat OSS)       : leader OSS, mature
Ory Hydra + Kratos           : modulaire, cloud-native
Authentik (OSS)              : moderne, alternative
Zitadel (OSS + SaaS)         : multi-tenant natif
Authelia (OSS)               : léger, self-hosting homelab

SaaS OpenID Providers

Auth0 (Okta)                 : leader SaaS
Microsoft Entra ID            : dominant entreprise M365
Okta Customer Identity       : enterprise
Google Identity Platform     : GCP, grand public via Google Sign-In
Amazon Cognito               : AWS-friendly
Clerk                        : dev-friendly, moderne
Stytch                       : passwordless-first
WorkOS                       : SSO B2B dev-friendly

Bonnes pratiques 2026

  1. Authorization Code + PKCE pour tous les nouveaux clients, publics ou confidentiels.
  2. Bannir Implicit et ROPC explicitement dans les politiques.
  3. Whitelister strict des redirect_uri (exact match, pas de wildcards).
  4. State et nonce aléatoires à chaque requête authorize, cryptographiquement sécurisés.
  5. Validation JWT via bibliothèque, avec algorithms=["RS256"] explicite.
  6. Refresh tokens avec rotation (RFC 6749 bis draft), jamais stockés en JavaScript.
  7. Tokens court-durée : Access Token 15 min max, Refresh Token 7-30 jours.
  8. Logout propre via end_session_endpoint OIDC + révocation côté OP.
  9. Monitoring des flows : alertes sur anomalies (changement d'IP, nouveau device).
  10. Workload Identity Federation pour tout CI/CD, remplacer toutes les clés statiques cloud.

Points clés à retenir

  • OIDC = couche d'authentification standardisée 2014 sur OAuth 2.0. Fournit un ID Token JWT avec l'identité vérifiée de l'utilisateur.
  • OAuth 2.0 = framework d'autorisation (accès ressources). OIDC = authentification (qui est l'utilisateur). OIDC inclut OAuth 2.0 sous-jacent.
  • Flow recommandé 2026 : Authorization Code + PKCE (RFC 7636) pour tout. Implicit et ROPC dépréciés par OAuth 2.1.
  • ID Token = JWT destiné au client. Access Token = destiné à l'API. Ne jamais confondre les deux : vulnérabilité token substitution.
  • Validation JWT obligatoire : signature (via JWKS), iss, aud, exp, nonce. Toujours whitelister algorithmes. Bannir alg:none.
  • 7 attaques courantes : alg:none, confusion HS256/RS256, open redirect, CSRF sans state, replay sans nonce, token substitution, SSRF via URI.
  • Workload Identity Federation : remplacer les clés statiques cloud (AWS access keys, GCP JSON, Azure secrets) par JWT OIDC échangé contre credentials court-durée. Natif GitHub Actions, GitLab CI, CircleCI.
  • OpenID Providers self-hosted : Keycloak, Ory Hydra+Kratos, Authentik, Zitadel. SaaS leaders : Auth0, Entra ID, Okta, Cognito, Clerk.

Pour comprendre comment sécuriser l'autorisation après authentification OIDC (A01 OWASP), voir Broken Access Control : explication, exemples et prévention. Pour sécuriser les entrées utilisateur reçues via le flow (redirect_uri, state, code), lire Validation des entrées : bonnes pratiques secure coding 2026. Pour resituer OIDC dans la roadmap AppSec complète d'un développeur, la roadmap AppSec Engineer 2026 détaille les étapes.

Questions fréquentes

  • Quelle est la différence entre OAuth 2.0 et OpenID Connect ?
    OAuth 2.0 est un framework d'autorisation : il permet à une application d'obtenir un accès limité à des ressources protégées au nom de l'utilisateur (par exemple lire les fichiers Google Drive d'un utilisateur). Il ne décrit pas explicitement qui est l'utilisateur. OpenID Connect (OIDC) est une couche d'authentification construite au-dessus de OAuth 2.0 qui ajoute un ID Token (JWT) contenant l'identité vérifiée de l'utilisateur. Simplifié : OAuth = autorisation, OIDC = authentification et autorisation combinées.
  • Quel flow OIDC utiliser en 2026 ?
    Authorization Code avec PKCE pour tous les clients publics (SPA, mobile, desktop). Authorization Code classique (avec client secret) pour les applications web server-side. Client Credentials pour service-to-service. Device Authorization pour TV et IoT sans clavier. Les flows Implicit et Resource Owner Password Credentials (ROPC) sont dépréciés depuis OAuth 2.0 Security Best Current Practice (BCP draft-ietf-oauth-security-topics) et ne doivent plus être utilisés dans de nouveaux déploiements.
  • Qu'est-ce que PKCE et pourquoi c'est obligatoire ?
    PKCE (Proof Key for Code Exchange, RFC 7636) est une extension de l'Authorization Code flow qui empêche l'interception du code d'autorisation. Le client génère un secret local (code_verifier), envoie son hash (code_challenge) dans la requête d'autorisation, puis prouve la possession du secret en échangeant le code contre un token. Un attaquant qui intercepte le code ne peut pas l'échanger sans le code_verifier. Obligatoire pour tous les clients publics depuis OAuth 2.1 (2024) et fortement recommandé même pour les clients confidentiels.
  • Un ID Token peut-il servir pour appeler une API ?
    Non. L'ID Token contient l'identité de l'utilisateur et prouve qu'il s'est authentifié - il est destiné au client (relying party) qui l'a demandé. L'Access Token est destiné à l'API et prouve les autorisations. Confondre les deux est une erreur classique. Les APIs doivent valider l'Access Token (signature, issuer, audience, expiration, scopes) - pas l'ID Token. De plus, l'ID Token a une audience spécifique (le client_id du relying party), et une API qui l'accepte expose des attaques de token substitution.
  • Comment valider correctement un JWT ID Token ?
    Cinq étapes obligatoires. 1) Vérifier la signature cryptographique avec la clé publique du provider (obtenue via l'endpoint JWKS du provider). 2) Vérifier `iss` (issuer) correspond à l'OpenID Provider attendu. 3) Vérifier `aud` (audience) contient le client_id. 4) Vérifier `exp` (expiration) n'est pas dépassé. 5) Vérifier `nonce` correspond à celui envoyé initialement (protection replay). Ne jamais faire confiance à `alg: none` ou à des algorithmes HS256 si on attendait RS256 (attaque de confusion d'algorithme). Utiliser une bibliothèque éprouvée plutôt que d'implémenter soi-même.
  • Comment utiliser OIDC pour CI/CD sans secrets long-durée ?
    Via Workload Identity Federation. Le runner CI/CD (GitHub Actions, GitLab CI, CircleCI) émet un JWT OIDC signé décrivant le contexte (repo, branche, environment). Le cloud provider (AWS, GCP, Azure) est configuré pour faire confiance à ce provider OIDC et échange le JWT contre des credentials cloud court-durée (1-2 heures). Avantage : plus de clés statiques stockées dans secrets CI. GitHub Actions supporte nativement via `permissions: id-token: write`. Adopté massivement depuis 2022-2023 pour remplacer les clés JSON et AWS access keys statiques.

Écrit par

Naim Aouaichia

Expert cybersécurité et fondateur de Zeroday Cyber Academy

Expert cybersécurité avec un master spécialisé et un parcours hybride : développement, DevOps, DevSecOps, SOC, GRC. Fondateur de Hash24Security et Zeroday Cyber Academy. Formateur et créateur de contenu technique sur la cybersécurité appliquée, la sécurité des LLM et le DevSecOps.