Getting Started with DPoP
This guide walks you through enabling DPoP (Demonstration of Proof-of-Possession) support in your Auth0-protected ASP.NET Core API.
Prerequisites
Before enabling DPoP, ensure you have:
- ✅ An Auth0 account with DPoP enabled (contact Auth0 support if needed)
- ✅ An API configured in Auth0 with DPoP support
- ✅ The Auth0 ASP.NET Core API Authentication library installed
- ✅ Basic Auth0 authentication already configured (see Getting Started)
Quick Start
Step 1: Enable DPoP with Default Settings
Add .WithDPoP() to your authentication configuration:
using Auth0.AspNetCore.Authentication.Api;
using Microsoft.AspNetCore.Authentication.JwtBearer;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuth0ApiAuthentication(options =>
{
options.Domain = builder.Configuration["Auth0:Domain"];
options.JwtBearerOptions = new JwtBearerOptions()
{
Audience = builder.Configuration["Auth0:Audience"]
};
}).WithDPoP(); // ✨ Enable DPoP with default settings
builder.Services.AddAuthorization();
builder.Services.AddControllers();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
That's it! Your API now supports DPoP validation with sensible defaults.
Step 2: Configure Auth0
Ensure your Auth0 API is configured to issue DPoP-bound tokens. Follow the Auth0 DPoP configuration guide to set up DPoP for your API and clients.
Note: DPoP requires Auth0 tenant configuration. Contact Auth0 support if you don't see DPoP options.
Step 3: Test Your API
With DPoP (will succeed)
curl -X GET https://localhost:5001/api/protected \
-H "Authorization: DPoP <dpop-bound-access-token>" \
-H "DPoP: <dpop-proof-token>"
Without DPoP (will also succeed with default Allowed mode)
curl -X GET https://localhost:5001/api/protected \
-H "Authorization: Bearer <regular-access-token>"
DPoP Modes Explained
Allowed Mode (Default)
.WithDPoP(options =>
{
options.Mode = DPoPModes.Allowed;
});
Behavior:
- ✅ Accepts DPoP-bound tokens with valid proofs
- ✅ Also accepts standard Bearer tokens
- 🔍 Validates DPoP when the
DPoPheader is present
Required Mode
.WithDPoP(options =>
{
options.Mode = DPoPModes.Required;
});
Behavior:
- ✅ Only accepts DPoP-bound tokens with valid proofs
- ❌ Rejects standard Bearer tokens
- ❌ Rejects requests without the
DPoPheader
Disabled Mode
.WithDPoP(options =>
{
options.Mode = DPoPModes.Disabled;
});
Behavior:
- ✅ Only standard JWT Bearer authentication
- ❌ No DPoP validation performed
- 🚫 DPoP headers are ignored
Common Configuration Examples
Example 1: Allowed Mode
Start with Allowed mode to test DPoP without breaking existing clients:
builder.Services.AddAuth0ApiAuthentication(options =>
{
options.Domain = builder.Configuration["Auth0:Domain"];
options.JwtBearerOptions = new JwtBearerOptions()
{
Audience = builder.Configuration["Auth0:Audience"]
};
}).WithDPoP(options =>
{
options.Mode = DPoPModes.Allowed;
options.Leeway = 30; // 30 seconds tolerance
options.IatOffset = 300; // 5 minutes max age
});
Example 2: Required Mode
Enforce DPoP for all requests:
builder.Services.AddAuth0ApiAuthentication(options =>
{
options.Domain = builder.Configuration["Auth0:Domain"];
options.JwtBearerOptions = new JwtBearerOptions()
{
Audience = builder.Configuration["Auth0:Audience"]
};
}).WithDPoP(options =>
{
options.Mode = DPoPModes.Required;
options.Leeway = 10; // Tighter timing
options.IatOffset = 120; // 2 minutes max age
});
Example 3: Custom Authentication Scheme
Use a custom scheme name:
builder.Services
.AddAuthentication("MyCustomScheme")
.AddAuth0ApiAuthentication("MyCustomScheme", options =>
{
options.Domain = builder.Configuration["Auth0:Domain"];
options.JwtBearerOptions = new JwtBearerOptions()
{
Audience = builder.Configuration["Auth0:Audience"]
};
})
.WithDPoP("MyCustomScheme", options =>
{
options.Mode = DPoPModes.Allowed;
});
Protecting Endpoints
Once DPoP is enabled, protect your endpoints as usual:
Using Minimal APIs
app.MapGet("/api/public", () =>
Results.Ok("Public endpoint - no authentication required"));
app.MapGet("/api/protected", () =>
Results.Ok("Protected endpoint - authentication required"))
.RequireAuthorization();
Using Controllers
[ApiController]
[Route("api/[controller]")]
public class DataController : ControllerBase
{
[HttpGet("public")]
public IActionResult Public()
{
return Ok("Public endpoint");
}
[Authorize]
[HttpGet("protected")]
public IActionResult Protected()
{
return Ok("Protected endpoint");
}
}
Accessing Claims
DPoP validation is transparent - access claims normally:
[Authorize]
[HttpGet("user-info")]
public IActionResult GetUserInfo()
{
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
var email = User.FindFirst(ClaimTypes.Email)?.Value;
return Ok(new { userId, email });
}
Troubleshooting
DPoP Validation Fails
Problem: Requests with DPoP header are rejected
Solutions:
- Check that Auth0 issued a DPoP-bound token (look for
cnfclaim) - Verify the
DPoPproof is properly formed - Ensure
htm(HTTP method) andhtu(HTTP URI) match exactly - Check time synchronization -
iatmust be recent
Bearer Tokens Rejected in Required Mode
Problem: Standard bearer tokens return 401
Solution: This is expected behavior in Required mode. Either:
- Switch to
DPoPModes.Allowedto support both - Update clients to send DPoP proofs
Time Validation Errors
Problem: Valid-looking DPoP proofs are rejected due to timing
Solutions:
- Increase
IatOffsetto allow older proofs - Increase
Leewayfor clock skew tolerance - Ensure client and server clocks are synchronized
.WithDPoP(options =>
{
options.IatOffset = 600; // 10 minutes
options.Leeway = 60; // 1 minute leeway
});
Error Responses
Invalid DPoP Proof
HTTP/1.1 401 Unauthorized
WWW-Authenticate: DPoP error="invalid_dpop_proof",
error_description="DPoP proof validation failed"
Missing DPoP Proof (Required Mode)
HTTP/1.1 401 Unauthorized
WWW-Authenticate: DPoP error="invalid_request",
error_description="DPoP proof is missing"
Invalid Token
HTTP/1.1 401 Unauthorized
WWW-Authenticate: DPoP error="invalid_token",
error_description="The cnf (confirmation) claim is missing or invalid"
Next Steps
- DPoP Configuration - Detailed configuration options
- DPoP Overview - Understanding DPoP concepts
- Configuration Guide - General Auth0 configuration