100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

OAuth Best Practices

The concrete, RFC 9700-aligned security practices every OAuth 2.0 implementation should follow, from PKCE to token storage.

PracticeAdvanced10 min readJul 10, 2026
Analogies

OAuth Best Practices

OAuth 2.0 is a framework, not a turnkey protocol, so implementers must make dozens of security-relevant decisions themselves. Getting those decisions wrong is the leading cause of real-world OAuth vulnerabilities, from authorization code interception to token leakage via referrer headers or browser history. The practices below, largely codified in RFC 9700 (the OAuth 2.0 Security Best Current Practice), apply to almost every deployment regardless of grant type or client platform.

🏏

Cricket analogy: Just as the laws of cricket leave field-placement strategy to the captain, OAuth leaves security choices to implementers, and a captain like Rohit Sharma who sets a sloppy field concedes runs the way a sloppy OAuth client concedes tokens.

Always Use PKCE and the State Parameter

RFC 9700 now mandates Proof Key for Code Exchange (PKCE) for every authorization code flow, not just public clients on mobile and single-page apps. The client generates a random code_verifier, derives a code_challenge via SHA-256, sends the challenge in the authorization request, and later presents the original verifier at the token endpoint so the authorization server can confirm the code redemption came from the same party that started the flow. Separately, the state parameter — a unique, unguessable value tied to the user's session — must be generated per request and validated on return to block cross-site request forgery attacks that trick a victim into completing another attacker's authorization flow.

🏏

Cricket analogy: PKCE is like a bowler and wicketkeeper agreeing on a secret signal before the over starts, so if someone from outside the field tries to fake a run-out call, like in a contested Ashes appeal, the umpire can check the signal matches.

http
GET /authorize?response_type=code
  &client_id=s6BhdRkqt3
  &redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
  &scope=openid%20profile%20orders.read
  &state=af0ifjsldkj
  &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
  &code_challenge_method=S256 HTTP/1.1
Host: auth.example.com

# Later, at the token endpoint the client redeems the code and
# proves possession of the verifier that produced the challenge:
POST /token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
&client_id=s6BhdRkqt3
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

RFC 9700 (2025) deprecates the implicit grant entirely and requires PKCE for all authorization code clients, public and confidential alike, because PKCE protects against authorization code injection regardless of whether the client can also keep a client secret.

Secure Token Storage and Transmission

Access tokens and refresh tokens are bearer credentials: whoever holds them can use them, so where and how they're stored matters as much as how they're issued. For browser-based apps, storing tokens in localStorage or sessionStorage exposes them to any script that runs on the page, so a single cross-site scripting bug anywhere in the app's dependency tree can exfiltrate every active session; httpOnly, Secure, SameSite=Lax cookies scoped to a narrow path are far safer because JavaScript cannot read them. For server-side and native apps, tokens should be encrypted at rest, transmitted only over TLS 1.2+, and access tokens kept short-lived (minutes to a couple of hours) with refresh token rotation so a leaked refresh token has a limited blast radius and reuse can be detected.

🏏

Cricket analogy: Keeping a token in localStorage is like leaving the dressing-room door unlocked during a Test at Lord's — anyone who slips past reception, like a rogue photographer, can walk off with the team's playing strategy notes.

Never store OAuth access or refresh tokens in localStorage or sessionStorage for browser-based applications. A single XSS vulnerability anywhere in your JavaScript dependency chain gives an attacker a trivial way to read and exfiltrate them. Use httpOnly, Secure cookies or the Backend-for-Frontend (BFF) pattern instead.

Redirect URI Validation and Scope Minimization

Authorization servers must validate redirect_uri against an exact, pre-registered value — not a prefix match, not a wildcard subdomain match — because any looseness here becomes an open redirect that lets an attacker redirect the authorization code or token to a server they control. Clients should likewise request the narrowest set of scopes that the current operation needs rather than a broad, standing grant; a reporting dashboard that only reads order totals should request orders.read, not orders.write or admin scopes it will never use. Combining tight redirect URI matching with least-privilege scoping and, where supported, sender-constrained tokens (DPoP or mutual TLS) dramatically reduces what an attacker can do even if they manage to intercept a code or token.

🏏

Cricket analogy: Exact redirect URI matching is like a stadium checking that a ticket's exact seat number, not just its general stand, matches before letting someone in, the way Eden Gardens enforces seat-specific entry during IPL finals to stop scalpers.

  • PKCE is mandatory under RFC 9700 for all authorization code clients, public and confidential.
  • The state parameter must be a unique, unguessable value validated on every callback to prevent CSRF.
  • Never store tokens in localStorage or sessionStorage; prefer httpOnly Secure cookies or a BFF pattern.
  • Access tokens should be short-lived; refresh tokens should rotate and be revoked on reuse detection.
  • redirect_uri must be validated with exact string matching against a pre-registered value, never prefix or wildcard matching.
  • Request the narrowest scopes an operation actually needs rather than broad standing grants.
  • Sender-constrained tokens (DPoP or mTLS) limit the damage even if a token is intercepted.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#OAuth20StudyNotes#OAuthBestPractices#OAuth#Always#PKCE#State#StudyNotes#SkillVeris#ExamPrep