Authentication Security

OAuth Security Best Practices

Implement OAuth correctly to protect your users. Common mistakes and how to avoid them.

Security Best Practices

Always Use PKCE

Critical

Proof Key for Code Exchange prevents authorization code interception attacks. Required for public clients, recommended for all.

Implementation: Generate random code_verifier, hash to code_challenge, send with auth request.

Use State Parameter

Critical

Prevent CSRF attacks by including a random state parameter and validating it on callback.

Implementation: Generate random state, store in session, verify on callback.

Validate Redirect URIs

Critical

Only allow exact match redirect URIs. No wildcards, no open redirects.

Implementation: Whitelist exact callback URLs in OAuth provider settings.

Store Tokens Securely

High

Never store tokens in localStorage or expose to JavaScript. Use httpOnly cookies or secure server-side storage.

Implementation: httpOnly cookies for web, secure storage for mobile, encrypted database for servers.

Use Short-Lived Access Tokens

High

Limit damage from token theft with short expiration. Use refresh tokens for longer sessions.

Implementation: Access tokens: 15-60 minutes. Refresh tokens: days/weeks with rotation.

Request Minimal Scopes

Medium

Only request permissions your app actually needs. Reduces blast radius if compromised.

Implementation: Audit requested scopes. Remove unused ones. Request incrementally.

Common OAuth Mistakes

Storing tokens in localStorage

Risk: XSS attacks can steal tokens

Fix: Use httpOnly cookies or server-side session storage

Not validating state parameter

Risk: CSRF attacks can link attacker's account

Fix: Always generate, store, and validate state

Accepting authorization codes multiple times

Risk: Code reuse attacks

Fix: Invalidate codes after first use

Wildcard redirect URIs

Risk: Open redirect attacks can steal codes

Fix: Only allow exact match redirect URIs

Not using PKCE for SPAs

Risk: Authorization code interception

Fix: Always use PKCE for public clients

Long-lived access tokens

Risk: Extended window for token abuse

Fix: Use short-lived access tokens with refresh tokens

OAuth Flow Recommendations

Authorization Code + PKCERecommended

Use for: SPAs, mobile apps, server-side apps

Most secure flow for most use cases

Authorization Code (server-side)Recommended

Use for: Traditional server-rendered apps

Secure when client secret stays server-side

Implicit FlowAvoid

Use for: Legacy only—avoid for new apps

Deprecated. Token exposed in URL fragment.

Client CredentialsRecommended

Use for: Server-to-server authentication

No user involved. Secure for machine-to-machine.

Verify Your OAuth Implementation

VAS scans your application for common OAuth security issues including token exposure, missing PKCE, and insecure storage patterns.

Free Security Scan

Frequently Asked Questions

Do I need PKCE for server-side apps?

Technically not required for confidential clients with a client secret, but it adds defense in depth and is recommended. PKCE protects against authorization code interception even if the secret is compromised. Many OAuth providers now recommend or require it for all clients.

Where should I store OAuth tokens?

For web apps: httpOnly, secure, sameSite cookies for access tokens—they can't be stolen via XSS. For refresh tokens: httpOnly cookies or encrypted server-side storage. Never use localStorage or sessionStorage for tokens.

How do I handle token refresh securely?

Implement refresh token rotation—issue a new refresh token with each use and invalidate the old one. Store refresh tokens securely (httpOnly cookie or server-side). Set reasonable expiration and require re-authentication periodically.

What's the difference between state and nonce?

State prevents CSRF on the authorization request—it links the request to the session. Nonce (in OpenID Connect) prevents replay attacks on ID tokens—it links the token to the authentication request. Use both when implementing OIDC.

Should I implement OAuth myself or use a library?

Use a well-maintained library or OAuth provider SDK. OAuth has many subtle security requirements that are easy to get wrong. Libraries like NextAuth, Auth0 SDKs, or Passport.js handle the security details for you.

Last updated: January 16, 2026