Authorization · Information security · 4 min read
Implementing Modern OAuth Techniques: PAR, DPoP and More
Short answer
A modern OAuth 2.0 deployment uses the authorization code flow with PKCE for every client, exact redirect URI matching, short-lived tokens, and adds pushed authorization requests (RFC 9126), DPoP or mTLS sender-constrained tokens (RFC 9449, RFC 8705) and the iss response parameter (RFC 9207) where the risk justifies it.
Key takeaways
- RFC 9700 (January 2025) is the current OAuth 2.0 security best practice; the OAuth 2.1 draft folds much of it into one document.
- PAR keeps authorization parameters out of the browser and lets the server authenticate the client before the user ever sees a page.
- DPoP makes stolen access and refresh tokens much less useful without requiring mutual TLS.
OAuth 2.0 became an RFC in 2012, and the working group never stopped. Most of what has been added since closes holes found in real deployments. If your implementation still looks like a 2013 tutorial, this is the short list of what to change, roughly in order of value.
What is the baseline every OAuth deployment should meet?
Authorization code flow with PKCE for all clients, exact redirect URI matching, no implicit or password grants, and short-lived access tokens.
RFC 9700, the OAuth 2.0 Security Best Current Practice published in January 2025, sets out these rules. The OAuth 2.1 draft collects them into a single framework document so new implementers do not have to read a dozen RFCs.
- PKCE (RFC 7636) for public clients is required and for confidential clients recommended. Generate pairs with our PKCE Generator.
- Exact string matching of redirect URIs. No wildcards, no prefix matching.
- No implicit grant. Tokens in URL fragments leak through history, logs and Referer headers.
- No resource owner password grant. It trains users to type passwords into third-party apps and blocks MFA.
- Refresh tokens for public clients either sender-constrained or rotated on every use.
What are pushed authorization requests?
With PAR (RFC 9126), the client posts its authorization parameters directly to the server over a back channel and gets a short-lived request_uri, which is the only thing the browser carries.
Benefits: parameters cannot be tampered with in the browser, long requests no longer hit URL length limits, and the server authenticates the client before showing anything to the user. The front-channel request shrinks to client_id and request_uri. Servers can require PAR for specific clients.
What does DPoP add?
DPoP (RFC 9449) binds tokens to a key pair held by the client: each request carries a signed proof, so a stolen token cannot be replayed from another machine.
The client sends a DPoP header containing a JWT signed with its private key. The proof includes the HTTP method (htm), the URL (htu), a timestamp, a unique jti and, for resource requests, a hash of the access token (ath). The authorization server puts the key's thumbprint in the token's cnf.jkt claim. The API checks that the proof is fresh, matches the request and was signed by the bound key.
DPoP works at the application layer, so it suits single-page apps and mobile clients where mutual TLS is impractical. Where you control both ends and run a PKI, mTLS certificate-bound tokens (RFC 8705) achieve the same.
What is the iss parameter in authorization responses?
RFC 9207 has the authorization server add its issuer identifier to the redirect, so a client that talks to several servers can detect mix-up attacks.
A mix-up attack tricks a client into sending a code from one server to another. If the client checks that iss in the response equals the server it started with, the attack fails. Clients that use a single authorization server are less exposed, but the check is cheap.
Which other extensions are worth knowing?
Resource indicators, token exchange, JWT access tokens and rich authorization requests.
| Extension | RFC | Use it when |
|---|---|---|
| Resource indicators | RFC 8707 | Tokens should be limited to one API (resource parameter) |
| Token exchange | RFC 8693 | A service calls downstream APIs on a user's behalf |
| JWT access tokens | RFC 9068 | APIs validate tokens locally in a standard format |
| Rich authorization requests | RFC 9396 | Scopes are too coarse (payments, specific records) |
| JWT-secured authorization requests | RFC 9101 | Request parameters must be signed |
| Authorization server metadata | RFC 8414 | Clients should discover endpoints automatically |
How do I check my current implementation?
Build your current authorization request in the Authorization URL Builder and read the warnings, then decode a sample access token in the JWT Decoder to review its audience and lifetime.
Common findings: missing PKCE on confidential clients, state values that are not random, tokens that live for a day, and an aud claim that names every API in the company. The OAuth security guide explains each of these in more depth.
Questions
Is OAuth 2.1 finished?
No. As of November 2026 it is an IETF Internet-Draft (draft-ietf-oauth-v2-1). You can adopt its rules today because they mostly come from published RFCs such as RFC 7636 and RFC 9700.
Do I need all of these extensions?
No. PKCE, exact redirect matching and short token lifetimes are the baseline for everyone. PAR, DPoP and mTLS are worth it for higher-risk APIs such as payments, health or administration.
What is FAPI?
FAPI is a set of OpenID Foundation security profiles for high-value APIs, first developed for open banking. FAPI 2.0 requires many of the techniques in this article, including PAR and sender-constrained tokens.