
DPoP, PKCE, and mTLS: Modern OAuth Defences Demystified
โข by Opendata Consult Ltd
Introduction
OAuth 2.0 has long been the backbone of secure API access. But as threats evolved, so did the defences. Whether you're a fintech developer, an identity architect, or just someone who's been burned by a bad token design, understanding how to bind, constrain, and protect tokens is key.
In this article, we'll unpack three critical techniques:
- PKCE (Proof Key for Code Exchange)
- DPoP (Demonstration of Proof-of-Possession)
- mTLS (Mutual TLS)
We'll see where each shines, what problems they solve, and when you should (and shouldn't) use them.
OAuth Flow Types: Frontend vs Backend
OAuth supports multiple flows โ and each flow has different risk profiles.
๐ Frontend Flows (Interactive, with Users)
Examples: Authorization Code Flow (with PKCE), Implicit Flow (deprecated)
Used by: SPAs, mobile apps, user-driven apps
Risks: Token leakage in front-channel, code interception
๐ง Backend Flows (Non-interactive)
Examples: Client Credentials Grant, JWT Bearer Grant
Used by: B2B APIs, daemons, server-to-server integrations
Risks: Replay, impersonation, secrets leaking
What Are We Trying to Protect Against?
- Authorization Code Interception: Attacker snags a code from the redirect.
- Token Replay: An access token is reused by someone who shouldn't have it.
- Client Impersonation: Attacker pretends to be your client.
- Token Leakage in Front-Channel: Especially bad for SPAs or mobile apps.
๐ PKCE: The Mobile & SPA Lifeline
PKCE (pronounced "pixy") was introduced to save public clients from code interception. It's now mandatory in many specs (including OpenID Connect and Open Banking UK).
- Works without a client secret
- Solves the "intercepted code" problem
- Doesn't bind tokens to anything โ only validates that the same client who got the code is redeeming it
โ When to Use:
- SPAs
- Native mobile apps
- Authorization Code Flow for public clients
๐งพ Example PKCE Flow (Sequence Diagram)

๐งฌ Example PKCE Challenge Payload (JSON)
{
"code_challenge": "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM",
"code_challenge_method": "S256"
}
๐ชช DPoP: Tokens With a Memory
DPoP binds tokens and individual requests to a public/private key pair.
- Answers: โDid this client send this request?โ
- No certificate management required
- Access token is bound to a public key
โ When to Use:
- Clients with private key capability (but no certs)
- APIs requiring request integrity
- Fintech APIs in regions where mTLS is too heavy
๐ DPoP Flow (Sequence Diagram)
Sequence Diagram: Supporting Both SSA and Non-SSA Flows

๐งพ Example DPoP Proof JWT (Header + Payload)
{
"typ": "dpop+jwt",
"alg": "ES256",
"jwk": {
"kty": "EC",
"crv": "P-256",
"x": "f83OJ3D2xF4cbE3V4c7rB1JvVJtU0uvU2K9UsVkqW2I",
"y": "x_FEzRu9hIRGGrDXSEgYqd59RzKQffbkqf2c3M4e3-s"
}
}
{
"htu": "https://api.example.com/resource",
"htm": "GET",
"jti": "2f7d798b-3b1a-491e-98a9-bd0c692f1ebc",
"iat": 1711952793
}
๐ท mTLS: The Gold Standard for Token Binding
Mutual TLS is simple in concept: both server and client present certs, and the server checks that the access token was issued to a client with the matching cert.
- Requires mTLS client authentication
- Access token bound to certificate fingerprint
- Works best in server-to-server integrations
โ When to Use:
- Backend services
- Financial-grade APIs (Open Banking UK, Brasil)
- Highly regulated environments
๐ mTLS Flow (Sequence Diagram)

๐ Example mTLS Certificate Binding (Access Token Snippet)
{
"access_token": "eyJ...xyz",
"cnf": {
"x5t#S256": "aBcD1234EFgh5678..."
}
}
๐งช Comparison Table
Feature / Mechanism | PKCE | DPoP | mTLS |
---|---|---|---|
Token Binding | โ | โ | โ |
Client Auth | โ | โ | โ |
Request Binding | โ | โ | โ |
Replay Protection | โ | โ | โ |
Frontend Friendly | โ | โ | โ |
Key Management Req. | โ | โ | โ |
๐ So Which Should You Use?
Use Case | Useโฆ |
---|---|
SPA / Mobile App | PKCE |
Lightweight token binding | DPoP |
Strong client auth & binding | mTLS |
๐ง โBut What Aboutโฆ?โ
We could dive into:
- RAR (Rich Authorization Requests)
- JARM (JWT-secured Authorization Response Mode)
- CIBA (Client Initiated Backchannel Authentication)
...but we won't. These deserve their own deep dives โ and they're coming.
๐ Closing Thoughts
OAuth security isn't plug-and-play โ it's design-driven. Each of PKCE, DPoP, and mTLS is solving a different piece of the puzzle. As Fintechs and Open Banking APIs evolve, picking the right tool for the right threat is what separates the secure from the breached.