コンテンツにスキップ

DPoP

このコンテンツはまだ日本語訳がありません。

Overview

DPoP (Demonstrating Proof of Possession, RFC 9449) binds access tokens to a client’s cryptographic key pair, preventing token theft and replay attacks. Even if an access token is intercepted, it cannot be used without the corresponding private key.

The DPoP API is available at client.dpop.

Initialization

Initialize DPoP before making authentication requests:

await client.dpop.initialize();
if (client.dpop.isInitialized()) {
console.log('DPoP ready');
console.log('Thumbprint:', client.dpop.getThumbprint());
}

The SDK generates an asymmetric key pair and stores it for subsequent proof generation.

Generating DPoP Proofs

Generate a proof JWT for each HTTP request:

const proof = await client.dpop.generateProof('POST', 'https://auth.example.com/token');

For resource requests that include an access token, pass the token to generate the ath (access token hash) claim:

const accessToken = await client.token.getAccessToken();
const tokenHash = await client.dpop.calculateAccessTokenHash(accessToken);
const proof = await client.dpop.generateProof('GET', 'https://api.example.com/data', {
accessTokenHash: tokenHash,
});

Proof Options

ParameterTypeDescription
accessTokenHashstringBase64url-encoded SHA-256 hash of the access token
noncestringServer-provided nonce value

Nonce Handling

Authorization servers may require a nonce in DPoP proofs. When the server returns a DPoP-Nonce header, pass it to the SDK:

// Server responds with DPoP-Nonce header
client.dpop.handleNonceResponse(nonceFromServer);
// Subsequent proofs will include the nonce
const proof = await client.dpop.generateProof('POST', 'https://auth.example.com/token');

Checking Server Support

Verify that the authorization server supports DPoP:

const supported = await client.dpop.isServerSupported();
if (supported) {
await client.dpop.initialize();
}

This checks the dpop_signing_alg_values_supported field in the OIDC Discovery document.

DPoP Proof JWT Structure

Each proof is a signed JWT with the following structure:

{
"typ": "dpop+jwt",
"alg": "ES256",
"jwk": {
"kty": "EC",
"crv": "P-256",
"x": "...",
"y": "..."
}
}

Claims

{
"jti": "unique-id",
"htm": "POST",
"htu": "https://auth.example.com/token",
"iat": 1699876543,
"ath": "base64url-sha256-of-access-token",
"nonce": "server-provided-nonce"
}
ClaimTypeDescription
jtistringUnique proof identifier (prevents replay)
htmstringHTTP method (uppercase)
htustringHTTP URL (scheme + host + path, no query)
iatnumberIssued at timestamp
athstringAccess token hash (when using access token)
noncestringServer-provided nonce (when required)

Complete Example: Token Request with DPoP

const client = await createAuthrimClient({
issuer: 'https://auth.example.com',
clientId: 'my-app',
crypto: cryptoProvider, // Must implement DPoPCryptoProvider
storage: storageProvider,
http: httpClient,
});
// Initialize DPoP
if (await client.dpop.isServerSupported()) {
await client.dpop.initialize();
}
// Build authorization URL (DPoP is transparent to the auth flow)
const { url } = await client.buildAuthorizationUrl({
redirectUri: 'https://myapp.com/callback',
});
// After callback, tokens are automatically DPoP-bound
const tokens = await client.handleCallback(callbackUrl);
// Access token is now DPoP-bound (token_type: 'DPoP')
// The SDK automatically generates DPoP proofs when fetching tokens
const accessToken = await client.token.getAccessToken();

Clearing DPoP State

To reset the DPoP key pair (e.g., on logout):

await client.dpop.clear();

Public Key Access

Retrieve the current DPoP public key:

const jwk = client.dpop.getPublicKeyJwk();
console.log(jwk); // { kty: 'EC', crv: 'P-256', x: '...', y: '...' }
const thumbprint = client.dpop.getThumbprint();
console.log(thumbprint); // JWK thumbprint string

Error Handling

Error CodeDescriptionRecovery
dpop_key_generation_errorFailed to generate the key pairCheck CryptoProvider implementation
dpop_proof_generation_errorFailed to sign the proof JWTCheck key availability, reinitialize

References

Next Steps

  • PAR — Pushed Authorization Requests
  • JAR & JARM — Signed authorization requests and responses
  • Token Management — Token lifecycle management