DPoP Session Binding & Security
Standard Bearer tokens (JWTs) are vulnerable to intercept-and-replay attacks: if a token is stolen from client storage or intercepted in transit, an attacker can reuse it from any machine without restriction.
NexID Auth-DPoP mitigates this vulnerability by implementing DPoP (Demonstrating Proof-of-Possession) as defined in RFC 9449. DPoP cryptographically binds the access token to an ephemeral client key pair.
1. DPoP Handshake & Validation Lifecycle
The sequence below illustrates how a client registers its key during token acquisition and subsequently proves possession of that key when accessing protected application resources.
2. Ephemeral Client Keypair Generation
When a client session is initialized:
- The client browser generates an asymmetric cryptographic key pair using the Web Crypto API.
- The key pair uses a secure curve like P-256 or Ed25519.
- The private key is flagged as non-extractable (
extractable: false) so it cannot be read by malicious browser scripts or extension exploits.
3. DPoP Proof Generation
For every request sent to either the Central Auth Edge or a Downstream Application Server, the client must construct a short-lived DPoP Proof (a separate JWT).
DPoP Proof Headers
The proof includes the client’s public key as a JSON Web Key (jwk) in its header:
{
"typ": "dpop+jwt",
"alg": "ES256",
"jwk": {
"kty": "EC",
"x": "f83OJ3D2...",
"y": "x_da65ld...",
"crv": "P-256"
}
}DPoP Proof Payload
The payload includes claims that bind the proof to a specific HTTP request and timestamp, limiting reuse:
{
"jti": "80231a4c-4eb2-411a-8c54-4a4b868e4a90",
"htm": "POST",
"htu": "https://auth.domain.com/auth/token",
"iat": 1780339200
}jti: A unique random identifier for this specific request.htm: The HTTP method (e.g.,POST,GET).htu: The target HTTP URI (without query parameters).iat: The issue time (typically valid for no more than 60–120 seconds).
4. Token Cryptographic Binding (cnf claim)
When the Central Auth Edge generates an access token, it computes the SHA-256 thumbprint of the client’s public key (the jkt value). This thumbprint is baked into the final Access Token’s payload under the confirmation (cnf) claim:
{
"sub": "user_12345",
"aud": "app_1",
"permissions": 43,
"exp": 1782345600,
"cnf": {
"jkt": "0Z_A4_v81vB7L...T8pQ"
}
}5. Server-Side Verification
When a downstream application server or edge worker receives a request containing a DPoP-bound token, it verifies:
- Access Token Validity: Verifies the signature of the main access token using the auth server’s public key (fetched from JWKS).
- DPoP Proof Signature: Extracts the public
jwkfrom the DPoP proof header and uses it to verify the proof’s signature. - Key Matching: Computes the SHA-256 thumbprint (
jkt) of the public key inside the DPoP proof header and ensures it exactly matches thecnf.jktclaim inside the access token. - Context Constraints: Matches the
htmandhtuclaims in the proof payload with the actual incoming request’s method and URL. - Replay Check: Queries Upstash Redis to ensure the
jtihas not been used before.
JTI Replay Window
To prevent replay attacks, the jti is cached in Redis with a time-to-live (TTL) of 2 minutes. Any request attempting to reuse a jti within this window is immediately rejected with a 401 Unauthorized status.