Sécurité avancée des clients
Durcir vos clients OAuth avec les pushed authorization requests (PAR), les jetons liés à une clé (DPoP) et l'authentification client private_key_jwt.
Au-delà de PKCE et des secrets clients, Obexal implémente trois mécanismes standard pour les clients à fortes exigences : PAR protège l'intégrité de la requête d'autorisation, DPoP rend les jetons volés inutilisables, et private_key_jwt supprime totalement le secret partagé. Ils sont indépendants et se combinent librement ; les trois sont annoncés dans le document de découverte.
Les exemples utilisent accounts.obexal.com, le domaine par défaut. Avec un domaine personnalisé, c'est ce domaine qui est l'issuer.
Pushed Authorization Requests (PAR, RFC 9126)
Ce que ça fait : au lieu de placer tous les paramètres d'autorisation dans l'URL du navigateur, le client les pousse d'abord directement au serveur et reçoit un request_uri opaque à usage unique. Le navigateur ne transporte plus que cette référence : les paramètres ne peuvent pas être altérés en chemin et ne fuient pas dans l'historique, les journaux ou les referrers.
Quand l'utiliser : clients confidentiels à fortes exigences d'intégrité, déploiements de type FAPI, ou dès que la requête d'autorisation contient des paramètres que vous ne voulez pas exposer.
Poussez la requête (un client confidentiel doit s'authentifier ; la requête ne doit pas elle-même contenir de request_uri) :
curl -sS -X POST https://accounts.obexal.com/oauth/par \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d 'response_type=code' \
-d "client_id=$CLIENT_ID" \
-d 'redirect_uri=https://app.example.eu/callback' \
-d 'scope=openid profile email' \
-d 'state=xyz' \
-d "code_challenge=$CHALLENGE" \
-d 'code_challenge_method=S256'{ "request_uri": "urn:ietf:params:oauth:request_uri:3Zk9v2...", "expires_in": 90 }Puis redirigez le navigateur avec deux paramètres seulement :
https://accounts.obexal.com/oauth/authorize?client_id=<CLIENT_ID>&request_uri=urn:ietf:params:oauth:request_uri:3Zk9v2...Le request_uri est valable 90 secondes et consommé au premier usage. La suite du flux (échange du code, PKCE) est inchangée.
DPoP (RFC 9449) : des jetons liés à une clé
Ce que ça fait : lie l'access token à une paire de clés détenue par le client. Chaque requête porte une preuve JWT éphémère dans l'en-tête DPoP, et le jeton lui-même porte l'empreinte de la clé dans son claim cnf.jkt. Un jeton volé est inutilisable sans la clé privée.
Quand l'utiliser : tout client pour lequel le vol de jeton est un risque réaliste, et comme couche de durcissement des jetons d'agents IA.
La preuve est un JWT d'en-tête typ: dpop+jwt, signé en ES256 ou RS256, dont l'en-tête jwk contient la clé publique, et dont les claims sont : htm (méthode HTTP), htu (URL cible sans query), iat (au plus 60 secondes d'âge) et un jti unique (usage unique, contrôlé anti-rejeu). Quand le jeton est présenté à un endpoint de ressource, ajoutez ath, le hachage SHA-256 en base64url de l'access token.
Envoyez la preuve au token endpoint ; le jeton émis est alors lié et le token_type devient DPoP :
curl -sS -X POST https://accounts.obexal.com/oauth/token \
-H "DPoP: $DPOP_PROOF" \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d 'grant_type=client_credentials'
# 200 -> {"access_token":"<JWT avec cnf.jkt>","token_type":"DPoP",...}Utilisez ensuite le jeton avec une preuve fraîche à chaque appel, via le schéma d'autorisation DPoP :
curl -sS https://accounts.obexal.com/oauth/userinfo \
-H "Authorization: DPoP $ACCESS_TOKEN" \
-H "DPoP: $DPOP_PROOF"Un jeton lié présenté sans preuve valide correspondante est refusé (fail closed). Les jetons émis sans preuve restent des Bearer classiques : DPoP s'active requête par requête.
private_key_jwt (RFC 7523) : s'authentifier sans secret partagé
Ce que ça fait : le client s'authentifie en signant une courte assertion avec sa clé privée ; Obexal la vérifie contre le JWKS public enregistré pour ce client. Aucun secret ne transite, n'est stocké ni partagé.
Quand l'utiliser : clients confidentiels qui veulent éliminer la distribution de secrets, et identités machine où la rotation de clés se gouverne mieux que la rotation de secrets. Se marie naturellement avec PAR.
Enregistrez d'abord le jeu de clés publiques du client via le champ jwks de POST /v1/applications (ou mettez-le à jour ensuite avec PATCH). Authentifiez-vous ensuite au token endpoint ou à l'endpoint PAR avec une assertion à la place d'un secret :
- Signée en RS256, ES256 ou PS256.
issetsubtous deux égaux auclient_id.audégal à l'URL de l'issuer, ou à l'URL du token endpoint ou de l'endpoint PAR.expobligatoire ;jtiunique (fenêtre anti-rejeu de 10 minutes).
curl -sS -X POST https://accounts.obexal.com/oauth/token \
-d 'grant_type=client_credentials' \
-d 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
-d "client_assertion=$ASSERTION"Limites et remarques
- Obexal signe ses propres jetons (access tokens, ID tokens, logout tokens) en RS256 uniquement. Les algorithmes ES256 et PS256 ci-dessus concernent ce que signe votre client, pas le serveur.
- PAR, DPoP et
private_key_jwtsont indépendants : adoptez-les séparément ou ensemble. Un profil haute assurance combine les trois. - Pour valider ce que le serveur émet, voir Valider les jetons.