Skip to content
Introducing the next era of Duende IdentityServer. Read our CEO’s announcement

OIDC Client DPoP Support

DPoP (Demonstrating Proof of Possession) is an extension to OAuth 2.0 that provides proof-of-possession for access tokens. It binds tokens to a specific cryptographic key, preventing token theft and replay attacks.

DPoP support is provided by the Extensions package:

Terminal window
dotnet add package Duende.IdentityModel.OidcClient.Extensions

Use the JsonWebKeys helper to create a key pair:

using Duende.IdentityModel.OidcClient.DPoP;
// Create an RSA key (recommended for most scenarios)
var proofKey = JsonWebKeys.CreateRsaJson();
// Or create an ECDSA key (smaller, faster)
var proofKey = JsonWebKeys.CreateECDsaJson();
var options = new OidcClientOptions
{
Authority = "https://demo.duendesoftware.com",
ClientId = "native.dpop",
RedirectUri = "app://callback",
Scope = "openid profile api"
};
// Enable DPoP
options.ConfigureDPoP(proofKey);
var client = new OidcClient(options);
var loginResult = await client.LoginAsync();
if (!loginResult.IsError)
{
// Create a handler for DPoP-protected API calls
var handler = client.CreateDPoPHandler(
proofKey,
loginResult.RefreshToken
);
var apiClient = new HttpClient(handler);
var response = await apiClient.GetAsync("https://api.example.com/resource");
}

Helper class for generating DPoP proof keys:

MethodDescription
CreateRsa(algorithm)Creates an RSA JsonWebKey (default: PS256)
CreateRsaJson(algorithm)Creates an RSA key as JSON string
CreateECDsa(algorithm)Creates an ECDSA JsonWebKey (default: ES256)
CreateECDsaJson(algorithm)Creates an ECDSA key as JSON string

Configures the OidcClient to use DPoP for token requests:

// Using a JSON proof key string
options.ConfigureDPoP(proofKey);
// Using a custom proof token factory
options.ConfigureDPoP(
proofTokenFactory,
tokenEndpointInnerHandler, // Optional: custom handler for token endpoint
apiInnerHandler // Optional: custom handler for API calls
);

Creates an HTTP message handler for DPoP-protected API calls:

// Using a JSON proof key string
var handler = client.CreateDPoPHandler(proofKey, refreshToken);
// Using a custom proof token factory
var handler = client.CreateDPoPHandler(
proofTokenFactory,
refreshToken,
apiInnerHandler // Optional: custom inner handler
);

For advanced scenarios, implement IDPoPProofTokenFactory:

public class CustomProofTokenFactory : IDPoPProofTokenFactory
{
public DPoPProof CreateProofToken(DPoPProofRequest request)
{
// request.Url - The HTTP URL
// request.Method - The HTTP method (GET, POST, etc.)
// request.DPoPNonce - Server-provided nonce (if any)
// request.AccessToken - The access token (for ath claim)
var proofToken = // ... create JWT proof token
return new DPoPProof { ProofToken = proofToken };
}
}
PropertyTypeDescription
UrlstringThe HTTP URL of the request
MethodstringThe HTTP method (GET, POST, etc.)
DPoPNoncestringServer-provided nonce value
AccessTokenstringThe access token (for ath claim binding)

Low-level handler that adds DPoP proof tokens to requests:

var handler = new ProofTokenMessageHandler(
proofTokenFactory,
innerHandler,
logger // Optional: ILogger<ProofTokenMessageHandler>
);

The DPoPExtensions class provides helper methods:

MethodDescription
SetDPoPProofToken(request, proofToken)Adds the DPoP header to a request
GetDPoPNonce(response)Extracts the DPoP-Nonce from a response
GetDPoPUrl(request)Gets the URL for DPoP proof creation
  1. Generate keys on device - Create proof keys locally and store them securely
  2. Use appropriate key type - RSA (PS256) for broad compatibility, ECDSA (ES256) for performance
  3. Handle nonce requirements - The handler automatically handles server-provided nonces
  4. Persist keys securely - Use platform-specific secure storage