Fournisseur OIDC et OAuth 2.1
Comment Obexal implémente OpenID Connect et OAuth 2.1 : découverte, JWKS, flux supportés et non supportés, scopes, claims et types de clients.
Obexal est un fournisseur OpenID Connect conforme aux standards, bâti sur OAuth 2.1. Chaque application que vous déclarez (app web, SPA, service backend ou agent IA) est un client OAuth, et toute bibliothèque OIDC standard peut s'y intégrer : aucun SDK propriétaire à embarquer.
Découverte et JWKS
Le document de découverte est la source de vérité des endpoints et des capacités :
curl https://accounts.obexal.com/.well-known/openid-configuration{
"issuer": "https://accounts.obexal.com",
"authorization_endpoint": "https://accounts.obexal.com/oauth/authorize",
"pushed_authorization_request_endpoint": "https://accounts.obexal.com/oauth/par",
"token_endpoint": "https://accounts.obexal.com/oauth/token",
"userinfo_endpoint": "https://accounts.obexal.com/oauth/userinfo",
"jwks_uri": "https://accounts.obexal.com/.well-known/jwks.json",
"revocation_endpoint": "https://accounts.obexal.com/oauth/revoke",
"introspection_endpoint": "https://accounts.obexal.com/oauth/introspect",
"end_session_endpoint": "https://accounts.obexal.com/oauth/logout",
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code", "refresh_token", "client_credentials", "urn:ietf:params:oauth:grant-type:token-exchange"],
"code_challenge_methods_supported": ["S256"],
"id_token_signing_alg_values_supported": ["RS256"],
"scopes_supported": ["openid", "profile", "email"],
"token_endpoint_auth_methods_supported": ["none", "client_secret_basic", "client_secret_post", "private_key_jwt"]
}Le JWKS servi sur /.well-known/jwks.json ne contient que des clés publiques. Il publie la clé de signature active ainsi que les clés retirées non encore expirées : les jetons émis avant une rotation de clé restent donc vérifiables.
Les exemples utilisent accounts.obexal.com, le domaine par défaut. Si votre organisation utilise un domaine personnalisé, ce domaine devient l'issuer : remplacez-le partout.
Flux supportés
- Authorization code avec PKCE : le seul flux interactif. PKCE est obligatoire pour tous les clients, publics comme confidentiels ;
code_challenge_methoddoit valoirS256(plainest refusé, tout comme l'absence de challenge). - Client credentials : identité machine pour les services backend et les agents IA. Clients confidentiels uniquement ; le jeton porte un
subégal auclient_id, sans ID token ni refresh token. - Refresh token : rotatif, avec détection de rejeu. Voir Valider les jetons.
- Token exchange (RFC 8693) : délégation attribuable pour les agents IA. Voir Délégation par Token Exchange.
Volontairement non supportés : le flux implicite (response_type autre que code), le grant resource owner password et le grant device authorization. Tout autre grant_type reçoit l'erreur standard unsupported_grant_type. Les endpoints OAuth renvoient des erreurs conformes au protocole, de la forme {"error": "...", "error_description": "..."}.
Types de clients
| Type | Authentification au token endpoint | Usage typique |
|---|---|---|
| Public | none (pas de secret, PKCE seul) | SPA, app mobile, CLI |
| Confidentiel | client_secret_basic, client_secret_post ou private_key_jwt | App web côté serveur, service, agent IA |
Vous déclarez les clients dans la console d'administration ou via POST /v1/applications. Le secret d'un client confidentiel n'est renvoyé qu'une seule fois, à la création ; seule son empreinte SHA-256 est stockée. Les redirect URIs doivent être des URL absolues http(s), comparées à l'identique, sans joker.
Scopes et claims
Les scopes standard sont openid (obligatoire), profile et email.
L'access token est un JWT (en-tête typ: at+jwt, signé RS256) portant les claims iss, sub, aud (le client_id par défaut), client_id, exp, iat, jti, scope et tenant. Les jetons délégués ajoutent un claim act (l'agent qui agit), et les jetons liés par DPoP ajoutent cnf.jkt.
L'ID token (en-tête typ: JWT) porte iss, sub, aud, exp, iat, auth_time et nonce (s'il est fourni), plus :
groups: les noms des groupes de l'utilisateur, omis s'il n'appartient à aucun groupe.emailetemail_verifiedavec le scopeemail.given_name,family_name,nameetlocaleavec le scopeprofile, quand ils sont renseignés dans le profil d'annuaire.
Le flux authorization code, pas à pas
Générez un couple PKCE côté client :
VERIFIER=$(openssl rand -base64 60 | tr '+/' '-_' | tr -d '=\n')
CHALLENGE=$(printf '%s' "$VERIFIER" | openssl dgst -binary -sha256 | openssl base64 | tr '+/' '-_' | tr -d '=\n')Envoyez le navigateur de l'utilisateur vers l'endpoint d'autorisation. Avec une session Obexal valide, la réponse est un 302 vers votre redirect_uri ; sans session, l'utilisateur passe d'abord par la page de connexion hébergée puis revient ici.
curl -sS -i -b cookies.txt "https://accounts.obexal.com/oauth/authorize?response_type=code&client_id=app_a1b2c3&redirect_uri=https%3A%2F%2Fapp.example.eu%2Fcallback&scope=openid%20profile%20email&state=xyz&nonce=n-123&code_challenge=$CHALLENGE&code_challenge_method=S256"
# 302 Location: https://app.example.eu/callback?code=<CODE>&state=xyzÉchangez le code (usage unique ; un rejeu renvoie invalid_grant) :
curl -sS -X POST https://accounts.obexal.com/oauth/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=authorization_code' \
-d 'code=<CODE>' \
-d 'redirect_uri=https://app.example.eu/callback' \
-d 'client_id=app_a1b2c3' \
-d "code_verifier=$VERIFIER"{
"access_token": "<JWT RS256>",
"token_type": "Bearer",
"expires_in": 600,
"refresh_token": "<opaque>",
"id_token": "<JWT>",
"scope": "openid profile email"
}Un client confidentiel s'authentifie en plus de PKCE, par exemple avec -u "$CLIENT_ID:$CLIENT_SECRET" (HTTP Basic).
Identité machine : client_credentials
curl -sS -X POST https://accounts.obexal.com/oauth/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d 'grant_type=client_credentials' \
-d 'scope=read'
# 200 -> {"access_token":"<JWT>","token_type":"Bearer","expires_in":600,"scope":"read"}Le scope demandé doit être un sous-ensemble des scopes déclarés du client.
Pour aller plus loin
- Valider les jetons dans votre API : JWKS ou introspection, révocation, rotation des refresh.
- Sécurité avancée des clients : PAR, DPoP et
private_key_jwt. - Sessions et déconnexion : logout RP-initiated et Back-Channel Logout.
- Délégation par Token Exchange : des agents IA qui agissent au nom des utilisateurs.