OAuth2 dPoP Delphi

· Fonctionnalités

Les jetons d'accès OAuth 2.0 sont les clés de ton royaume d'API — et si quelqu'un en vole un, il peut l'utiliser depuis n'importe où. DPoP (Demonstrating Proof of Possession), défini dans la RFC 9449, résout ce problème en liant cryptographiquement les jetons au client qui les a demandés. Même si un jeton est intercepté, il devient inutile sans la clé privée du client.

À partir de sgcWebSockets 2026.4.0, les composants client et serveur OAuth2 incluent une prise en charge complète de DPoP. Cet article explique ce qu'est DPoP, comment il fonctionne et comment le configurer dans ton application Delphi.

Qu'est-ce que DPoP ?

En OAuth 2.0 standard, un jeton Bearer fonctionne comme de l'argent liquide — quiconque le détient peut le dépenser. Si un attaquant intercepte le jeton via un réseau compromis, des logs fuités ou un proxy malveillant, il a un accès complet à tes ressources protégées.

DPoP change cela en faisant fonctionner les jetons comme une carte de crédit avec un code PIN. Le jeton lui-même est lié à une clé publique, et chaque requête doit inclure un JWT de preuve signé par la clé privée correspondante. Le serveur vérifie que la preuve correspond à la clé liée avant d'accepter la requête.

Jeton Bearer (traditionnel)
Quiconque possède le jeton peut l'utiliser. Les jetons volés sont entièrement exploitables. Aucune preuve d'identité requise.
Jeton DPoP (contraint à l'émetteur)
Le jeton est lié à une paire de clés. Chaque requête exige une preuve signée fraîche. Les jetons volés sont sans valeur sans la clé privée.

Comment DPoP fonctionne

Le flux DPoP ajoute une étape cryptographique légère au processus OAuth2 standard :

1. Génération de clé — Le client génère une paire de clés asymétriques (ES256 ou RS256). La clé privée reste sur le client ; la clé publique est incluse en tant que JWK dans les preuves DPoP.

2. Requête de jeton — Lors de la demande d'un jeton d'accès, le client inclut un en-tête HTTP DPoP contenant un JWT de preuve signé. La preuve inclut la méthode HTTP, l'URL, l'horodatage et un identifiant unique.

3. Liaison du jeton — Le serveur d'autorisation vérifie la signature de la preuve, extrait le thumbprint JWK (hash SHA-256 de la clé publique) et le lie au jeton émis. La réponse contient token_type: DPoP au lieu de Bearer.

4. Accès à la ressource — Pour chaque appel API, le client envoie à la fois le jeton et une preuve DPoP fraîche. La preuve inclut un claim ath (hash SHA-256 du jeton d'accès), liant la preuve à ce jeton spécifique.

Dans une preuve DPoP

Une preuve DPoP est un JWT compact en trois parties : en-tête, payload et signature.

// Header - identifies the key and algorithm
{
  "typ": "dpop+jwt",
  "alg": "ES256",
  "jwk": {
    "kty": "EC",
    "crv": "P-256",
    "x": "cWs37kZLJMej6fpd...",
    "y": "e2bkcQGaBERgSZUb..."
  }
}
// Payload - proves freshness and binds to the request
{
  "htm": "POST",
  "htu": "https://auth.example.com/oauth/token",
  "iat": 1774950263,
  "jti": "F1AFCD1F-95F7-401B-A2F5-195A31DB1802",
  "ath": "fUHyO2r2Z3DZ53EsNr..."
}

Configurer DPoP dans sgcWebSockets

Étape 1 : générer une paire de clés ES256

Utilise OpenSSL pour générer une paire de clés sur courbe elliptique :

# Generate EC private key
openssl ecparam -name prime256v1 -genkey -noout -out dpop_private.pem
# Extract public key parameters
openssl ec -in dpop_private.pem -text -noout

Convertis les coordonnées X et Y de la clé publique en Base64URL pour construire le JWK :

{"kty":"EC","crv":"P-256","x":"cWs37kZLJMej6fpdyKaI8Gz6CE...","y":"e2bkcQGaBERgSZUbAGR-iOOM..."}

Étape 2 : configurer le client OAuth2

// Configure OAuth2 as usual
OAuth2.OAuth2Options.GrantType := auth2CodePKCE;
OAuth2.OAuth2Options.ClientId := 'your-client-id';
OAuth2.OAuth2Options.ClientSecret := 'your-client-secret';
OAuth2.AuthorizationServerOptions.AuthURL := 'https://auth.example.com/authorize';
OAuth2.AuthorizationServerOptions.TokenURL := 'https://auth.example.com/oauth/token';
// Enable DPoP
OAuth2.DPoPOptions.Enabled := True;
OAuth2.DPoPOptions.Algorithm := dpopES256;
OAuth2.DPoPOptions.PrivateKey.LoadFromFile('dpop_private.pem');
OAuth2.DPoPOptions.PublicKeyJWK := '{"kty":"EC","crv":"P-256","x":"...","y":"..."}';
// Start the OAuth2 flow - DPoP headers are added automatically
OAuth2.Start;

C'est tout. Le composant automatiquement :

Étape 3 : utiliser les preuves DPoP pour les appels API

Après avoir obtenu un jeton d'accès lié DPoP, génère une preuve pour chaque requête API :

var
  vProof: String;
begin
  // Generate a DPoP proof for the API call
  vProof := OAuth2.GetDPoPProof(
    'GET',
    'https://api.example.com/userinfo',
    OAuth2.AccessToken
  );
  // Include both headers in your HTTP request:
  //   Authorization: DPoP <access_token>
  //   DPoP: <proof_jwt>
  HTTPClient.Request.CustomHeaders.AddValue('Authorization',
    'DPoP ' + OAuth2.AccessToken);
  HTTPClient.Request.CustomHeaders.AddValue('DPoP', vProof);
  HTTPClient.Get('https://api.example.com/userinfo');
end;

Fournisseurs pris en charge

DPoP est déjà pris en charge par les principaux fournisseurs OAuth2 :

Auth0 Active DPoP dans les paramètres de l'application. Nécessite la prise en charge du nonce (gérée automatiquement).
Okta Configure DPoP dans les politiques d'accès du serveur d'autorisation. GA depuis 2024.
Microsoft Entra ID Prend en charge DPoP pour les clients confidentiels.
Ping Identity Prise en charge complète de DPoP dans PingOne et PingFederate.

Validation DPoP côté serveur

Le composant serveur OAuth2 de sgcWebSockets prend également en charge la validation DPoP. Lorsque OAuth2Options.DPoP est activé, le serveur automatiquement :

// Enable DPoP on the OAuth2 server
OAuth2Server.OAuth2Options.DPoP := True;
// Optional: custom validation via event
OAuth2Server.OnOAuth2ValidateDPoP := procedure(Sender: TObject;
  Connection: TsgcWSConnection;
  const DPoPProof, AccessToken: String;
  var IsValid: Boolean)
begin
  // Add custom checks here (e.g., verify against a key registry)
  IsValid := True;
end;

Référence API DPoP

Propriété / méthode Description
DPoPOptions.Enabled Active DPoP pour toutes les requêtes de jeton.
DPoPOptions.Algorithm dpopES256 (recommandé) ou dpopRS256.
DPoPOptions.PrivateKey Clé privée encodée PEM pour signer les preuves DPoP.
DPoPOptions.PublicKeyJWK Représentation JSON Web Key de la clé publique.
GetDPoPProof() Génère un JWT de preuve DPoP pour une méthode HTTP, URL et jeton d'accès spécifiques.
GetDPoPJWKThumbprint() Renvoie le thumbprint SHA-256 RFC 7638 de la clé publique.
DPoPNonce La valeur DPoP-Nonce actuelle du serveur (lecture seule).

Mets à niveau la sécurité de tes jetons

DPoP est la plus importante amélioration de la sécurité des jetons OAuth 2.0 depuis PKCE. Il élimine toute la classe d'attaques de vol de jeton avec un minimum de changements de code — définis simplement DPoPOptions.Enabled := True, fournis tes clés, et le composant sgcWebSockets s'occupe du reste.

La prise en charge de DPoP est disponible dans sgcWebSockets 2026.4.0 pour Delphi (DXE6 à D13) et .NET (.NET Framework 2.0 à .NET 9). Télécharge la dernière version sur esegece.com.