OIDC Client DPoP Support
import { LinkCard } from “@astrojs/starlight/components”;
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.
Installation
Section titled “Installation”DPoP support is provided by the Extensions package:
dotnet add package Duende.IdentityModel.OidcClient.ExtensionsQuick Start
Section titled “Quick Start”1. Generate a Proof Key
Section titled “1. Generate a Proof Key”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();2. Configure DPoP on OidcClientOptions
Section titled “2. Configure DPoP on OidcClientOptions”var options = new OidcClientOptions{ Authority = "https://demo.duendesoftware.com", ClientId = "native.dpop", RedirectUri = "app://callback", Scope = "openid profile api"};
// Enable DPoPoptions.ConfigureDPoP(proofKey);
var client = new OidcClient(options);3. Login and Make API Calls
Section titled “3. Login and Make API Calls”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");}API Reference
Section titled “API Reference”JsonWebKeys
Section titled “JsonWebKeys”Helper class for generating DPoP proof keys:
| Method | Description |
|---|---|
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 |
OidcClientExtensions.ConfigureDPoP
Section titled “OidcClientExtensions.ConfigureDPoP”Configures the OidcClient to use DPoP for token requests:
// Using a JSON proof key stringoptions.ConfigureDPoP(proofKey);
// Using a custom proof token factoryoptions.ConfigureDPoP( proofTokenFactory, tokenEndpointInnerHandler, // Optional: custom handler for token endpoint apiInnerHandler // Optional: custom handler for API calls);OidcClientExtensions.CreateDPoPHandler
Section titled “OidcClientExtensions.CreateDPoPHandler”Creates an HTTP message handler for DPoP-protected API calls:
// Using a JSON proof key stringvar handler = client.CreateDPoPHandler(proofKey, refreshToken);
// Using a custom proof token factoryvar handler = client.CreateDPoPHandler( proofTokenFactory, refreshToken, apiInnerHandler // Optional: custom inner handler);Custom Proof Token Factory
Section titled “Custom Proof Token Factory”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 }; }}DPoPProofRequest Properties
Section titled “DPoPProofRequest Properties”| Property | Type | Description |
|---|---|---|
Url | string | The HTTP URL of the request |
Method | string | The HTTP method (GET, POST, etc.) |
DPoPNonce | string | Server-provided nonce value |
AccessToken | string | The access token (for ath claim binding) |
ProofTokenMessageHandler
Section titled “ProofTokenMessageHandler”Low-level handler that adds DPoP proof tokens to requests:
var handler = new ProofTokenMessageHandler( proofTokenFactory, innerHandler, logger // Optional: ILogger<ProofTokenMessageHandler>);DPoP Extensions for HttpRequestMessage
Section titled “DPoP Extensions for HttpRequestMessage”The DPoPExtensions class provides helper methods:
| Method | Description |
|---|---|
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 |
Best Practices
Section titled “Best Practices”- Generate keys on device - Create proof keys locally and store them securely
- Use appropriate key type - RSA (PS256) for broad compatibility, ECDSA (ES256) for performance
- Handle nonce requirements - The handler automatically handles server-provided nonces
- Persist keys securely - Use platform-specific secure storage