OAuth 2.0 security: the essential RFC 9700 controls
RFC 9700 updates OAuth 2.0 security. Learn PKCE, exact redirect URIs, token rotation, audience validation and a practical implementation checklist.
- AUTHOR
- Karol Rapacz / Penetration Tester (OSCP, PNPT)
- PUBLISHED
- 9 July 2026
- READING TIME
- 11 min read
- TOPIC
- AppSec
OAuth 2.0 security involves much more than validating a JWT signature. Serious failures come from loose redirect matching, missing PKCE, tokens accepted by the wrong service, unprotected refresh tokens and obsolete grants. RFC 9700 consolidates current Best Current Practice and updates earlier OAuth guidance.
This guide turns the standard into a checklist for web, mobile, SPA and API deployments.
Default to Authorization Code with PKCE
Authorization Code Flow separates browser interaction from token exchange. PKCE binds the code to the client that initiated login: the client sends a hash of a random code_verifier and later presents the original value. A stolen code without the verifier becomes far less useful.
PKCE is essential for public clients such as mobile apps and SPAs and is valuable for confidential clients too. Use S256, generate the verifier cryptographically and never log it.
Do not select Implicit Grant or Resource Owner Password Credentials for new systems. Implicit exposes tokens through the browser channel; the password grant gives the application the user’s password and bypasses modern identity-provider controls.
Match redirect URIs exactly
The authorisation server should compare the complete pre-registered redirect URI. Wildcards, prefix matching and user-controlled destination parameters create code-theft paths.
Use separate registrations for environments. Do not let one production client redirect to arbitrary localhost, test domains and every subdomain. Mobile apps should prefer Universal Links or App Links bound to a controlled domain.
state binds the response to the initiating browser session and helps prevent CSRF. OpenID Connect also uses nonce to bind the ID token to the request.
Restrict tokens to the correct resource
Every resource server validates signature, issuer, audience, lifetime and required scope. A token minted for API A must not be accepted by API B merely because the same provider signed it.
Scopes describe permitted operations but do not replace object authorisation. Endpoints still verify user, tenant, owner and resource state. Our API penetration-testing checklist covers BOLA and function-level access in depth.
Keep access tokens short-lived. Higher-risk systems can use sender-constrained tokens such as DPoP or mTLS to reduce replay after theft.
Rotate refresh tokens and detect replay
A long-lived refresh token can be more valuable than a password. Public clients should use rotation: every exchange invalidates the previous token. Reuse of an older token signals theft and should revoke the token family.
Store refresh tokens in platform security storage. Server-side web apps should prefer a server session or HttpOnly, Secure cookies with appropriate SameSite. Never put tokens in URLs, localStorage, logs, analytics or error reports.
OAuth implementation checklist
- Authorization Code with PKCE
S256is the default. - Redirect URIs use exact matching.
- Random
stateandnoncevalues are verified. - APIs validate
iss,aud, lifetime and scope. - Tokens have minimal privilege and short lifetime.
- Refresh tokens rotate and replay triggers revocation.
- Confidential clients authenticate without embedding secrets in frontend code.
- Logs and telemetry redact codes and tokens.
- Logout, account suspension and incident response can revoke access.
- Every application and environment has a separate client registration.
Testing OAuth beyond a happy-path login
Modify the redirect URI, replay a code, use a token with the wrong audience, omit PKCE, replay a rotated refresh token and change identities during account linking. Verify gateway controls and every resource server independently.
RFC 9700 is the baseline; final security depends on the identity provider and application logic. To validate OAuth, OIDC and token flows against real abuse cases, contact Breachroad.
Negative flow tests
Do not test only a successful login. Substitute redirect_uri, replay a code, change the client, use a code without the correct PKCE verifier, replay a token and test response mix-up between issuers. The server must compare redirect URIs exactly and bind the code to client and transaction.
Constrain tokens by audience, scope and short lifetime; consider sender-constrained tokens at higher risk. Refresh tokens require rotation or another replay-detection mechanism consistent with the BCP. Log identifiers and validation outcomes without storing tokens. A legacy-flow migration needs usage telemetry and a retirement date.
Sources: RFC 9700, RFC 7636 — PKCE, OWASP API Security.


