I token di accesso OAuth 2.0 sono le chiavi del regno delle tue API: se qualcuno ne ruba uno, può usarlo da qualsiasi posto. DPoP (Demonstrating Proof of Possession), definito da RFC 9449, risolve il problema vincolando crittograficamente i token al client che li ha richiesti. Anche se un token viene intercettato, diventa inutile senza la chiave privata del client.
A partire da sgcWebSockets 2026.4.0, i componenti client e server OAuth2 includono il supporto completo a DPoP. Questo articolo spiega cos'è DPoP, come funziona e come configurarlo nella tua applicazione Delphi.
Cos'è DPoP?
In OAuth 2.0 standard, un Bearer token funziona come contanti: chi lo possiede può spenderlo. Se un attaccante intercetta il token tramite una rete compromessa, log trapelati o un proxy malevolo, ha pieno accesso alle tue risorse protette.
DPoP cambia tutto facendo funzionare i token come una carta di credito con PIN. Il token stesso è vincolato a una chiave pubblica e ogni richiesta deve includere un proof JWT firmato dalla corrispondente chiave privata. Il server verifica che il proof corrisponda alla chiave vincolata prima di accettare la richiesta.
|
Bearer Token (tradizionale) Chiunque possieda il token può usarlo. I token rubati sono pienamente sfruttabili. Non è richiesta prova d'identità. |
DPoP Token (sender-constrained) Il token è vincolato a una coppia di chiavi. Ogni richiesta richiede un nuovo proof firmato. I token rubati sono inutili senza la chiave privata. |
Come funziona DPoP
Il flusso DPoP aggiunge un leggero passo crittografico al processo standard OAuth2:
1. Generazione delle chiavi — Il client genera una coppia di chiavi asimmetriche (ES256 o RS256). La chiave privata resta sul client; quella pubblica viene inclusa come JWK nei proof DPoP.
2. Richiesta del token — Quando richiede un access token, il client include un header HTTP DPoP contenente un proof JWT firmato. Il proof include il metodo HTTP, l'URL, il timestamp e un identificatore univoco.
3. Binding del token — L'authorization server verifica la firma del proof, estrae il thumbprint JWK (hash SHA-256 della chiave pubblica) e lo vincola al token emesso. La risposta contiene token_type: DPoP invece di Bearer.
4. Accesso alle risorse — Per ogni chiamata API, il client invia sia il token sia un nuovo proof DPoP. Il proof include un claim ath (hash SHA-256 dell'access token), vincolando il proof a quello specifico token.
Inside a DPoP Proof
A DPoP proof is a compact JWT with three parts: header, payload, and 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..."
}
Configuring DPoP in sgcWebSockets
Step 1: Generate an ES256 Key Pair
Use OpenSSL to generate an elliptic curve key pair:
# 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
Converti le coordinate X e Y della chiave pubblica in Base64URL per costruire il JWK:
{"kty":"EC","crv":"P-256","x":"cWs37kZLJMej6fpdyKaI8Gz6CE...","y":"e2bkcQGaBERgSZUbAGR-iOOM..."}
Passo 2: configurare il 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;
Tutto qui. Il componente automaticamente:
- Genera un nuovo proof DPoP JWT per ogni richiesta di token
- Gestisce le challenge
DPoP-Noncedel server e i retry in modo trasparente - Memorizza il nonce per le richieste successive
Step 3: Use DPoP Proofs for API Calls
After obtaining a DPoP-bound access token, generate a proof for each API request:
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;
Supported Providers
DPoP is already supported by major OAuth2 providers:
| Auth0 | Abilita DPoP nelle impostazioni dell'applicazione. Richiede il supporto al nonce (gestito automaticamente). |
| Okta | Configura DPoP nelle policy di accesso dell'authorization server. GA dal 2024. |
| Microsoft Entra ID | Supporta DPoP per i client confidenziali. |
| Ping Identity | Supporto completo a DPoP in PingOne e PingFederate. |
Server-Side DPoP Validation
The sgcWebSockets OAuth2 server component also supports DPoP validation. When OAuth2Options.DPoP is enabled, the server automatically:
- Valida i proof JWT DPoP (firma, claim, freshness)
- Vincola i token al thumbprint JWK del client
- Restituisce
token_type: DPoPper i token vincolati a DPoP - Rifiuta le richieste con proof invalidi o mancanti (restituisce 400
invalid_dpop_proof) - Verifica il claim
ath(hash dell'access token) sulle richieste di risorse
// 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;
Riferimento API DPoP
| Proprietà / metodo | Descrizione |
|---|---|
DPoPOptions.Enabled |
Abilita DPoP per tutte le richieste di token. |
DPoPOptions.Algorithm |
dpopES256 (consigliato) o dpopRS256. |
DPoPOptions.PrivateKey |
Chiave privata in PEM per firmare i proof DPoP. |
DPoPOptions.PublicKeyJWK |
Rappresentazione JSON Web Key della chiave pubblica. |
GetDPoPProof() |
Genera un proof DPoP JWT per un metodo HTTP, URL e access token specifici. |
GetDPoPJWKThumbprint() |
Restituisce il thumbprint SHA-256 (RFC 7638) della chiave pubblica. |
DPoPNonce |
Il valore corrente del DPoP-Nonce dal server (sola lettura). |
Upgrade Your Token Security
DPoP is the most significant improvement to OAuth 2.0 token security since PKCE. It eliminates the entire class of token theft attacks with minimal code changes — just set DPoPOptions.Enabled := True, provide your keys, and the sgcWebSockets component handles the rest.
Il supporto a DPoP è disponibile in sgcWebSockets 2026.4.0 sia per Delphi (da DXE6 a D13) sia per .NET (da .NET Framework 2.0 a .NET 9). Scarica l'ultima versione su esegece.com.
