# DPoP (Demonstrating Proof of Possession)

DPoP binds access tokens to your client so stolen tokens are useless to attackers.

## Why DPoP?

Normal OAuth tokens are "bearer" tokens, whoever has the token can use it. If your token leaks through logs, network interception, or a compromised server, an attacker can use it until it expires.

DPoP ties each token to a cryptographic key pair. Your app proves it holds the private key on every request. Steal the token? Doesn't matter - you can't use it without the key.

Think of it like chip + PIN vs. a credit card number. Anyone can use a stolen card number. With chip + PIN, you need the physical card.

Use DPoP for financial transactions, sensitive data access, or any scenario where token theft would be a big problem.

## How It Works

1. Generate a key pair for your client
2. On token requests, include a signed DPoP proof JWT in the `DPoP` header
3. The server binds your token to your public key
4. On API requests, include both the token and a fresh DPoP proof
5. The resource server verifies the proof matches the token's bound key


## DPoP Proof Structure

The proof is a JWT with your public key in the header:


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

The payload ties the proof to a specific request:


```json
{
  "jti": "unique-id",
  "htm": "GET",
  "htu": "https://api.business.jiko.io/api/v2/pockets/",
  "iat": 1711910400
}
```

- `jti` - unique ID (prevents replay)
- `htm` - HTTP method
- `htu` - URL you're calling
- `iat` - timestamp (10 second leeway)


## Token Request

Include the DPoP proof when getting tokens:


```http
POST /api/oauth2/token HTTP/1.1
Host: auth.jiko.io
Content-Type: application/x-www-form-urlencoded
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2In0...

grant_type=authorization_code&
client_id=your-client-id&
client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&
client_assertion=eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9...
```

Response:


```json
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI...",
  "token_type": "DPoP",
  "expires_in": 900
}
```

Note `token_type` is `DPoP`, not `Bearer`.

## API Requests

Every request needs the token and a fresh proof:


```http
GET /api/v2/pockets/ HTTP/1.1
Host: api.business.jiko.io
Authorization: DPoP eyJhbGciOiJSUzI1NiIsInR5cCI...
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2In0...
```

Generate a new proof for each request with a unique `jti`, correct `htm`/`htu`, and fresh `iat`.

## What DPoP Protects Against

| Threat | Bearer Token | DPoP Token |
|  --- | --- | --- |
| Token in logs | Attacker can use it | Useless without key |
| Token intercepted | Attacker can use it | Useless without key |
| Token leaked via XSS | Attacker can use it | Useless without key |
| Replay attacks | Works until expiry | Blocked by unique `jti` |


## References

- [RFC 9449](https://datatracker.ietf.org/doc/html/rfc9449) - DPoP specification
- [OAuth 2.0 Security BCP](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics) - recommends sender-constrained tokens