K-Lab
Loading OAuth 2.0 Authorization Code Flow visualizer...
About this tool

How the Authorization Code flow works

The OAuth 2.0 Authorization Code flow with PKCE is the recommended way for applications to obtain access tokens without exposing user credentials. The flow involves four parties: the client application, the user, the authorization server, and the resource server (API). The client redirects the user to the authorization server's login page, the user authenticates and grants permission, the authorization server redirects back to the client with a short-lived authorization code, and the client exchanges that code for access and refresh tokens via a secure back-channel request. This separation between the front-channel (browser redirects) and back-channel (server-to-server POST) is what makes the flow secure.

The access tokens issued by OAuth authorization servers are frequently JWTs (JSON Web Tokens) that encode the user's identity, permissions, and token expiration as signed claims. Use the JWT Debugger to decode and inspect these tokens during development. Understanding the token structure helps you debug authorization failures and verify that scopes and claims match your application's requirements.

OAuth security considerations

Implementing OAuth correctly requires attention to several security details beyond the basic flow. Always validate the state parameter to prevent CSRF attacks. Use PKCE even for confidential clients, as it provides defense-in-depth against authorization code interception. Store refresh tokens securely and implement token rotation so that a compromised refresh token can be detected when both the attacker and the legitimate client attempt to use it. Set short access token lifetimes (5-15 minutes) and rely on refresh tokens for session continuity.

When your application calls APIs using OAuth access tokens and receives 401 or 403 errors, proper retry logic prevents unnecessary user-facing failures. A token might expire between the time you check it and the time the API validates it. Use the Retry Calculator to model retry strategies that include token refresh as part of the retry cycle, and check CORS headers with the CORS Tester if your single-page app's token exchange requests are being blocked by the browser.

Frequently Asked Questions

Why should I not use the Implicit flow?

The OAuth 2.0 Implicit flow was originally designed for browser-based applications that could not securely store a client secret, delivering the access token directly in the URL fragment after authorization. This approach has several critical security problems that led the OAuth Security Best Current Practice (RFC 9700) to recommend against its use. First, the access token is exposed in the browser's URL bar and navigation history, making it visible to anyone with physical access to the device or any browser extension with history permissions. Second, the token can leak through the HTTP Referer header if the page loads any external resources. Third, the Implicit flow has no mechanism to bind the token to the specific client that requested it, making it vulnerable to token injection attacks where an attacker substitutes a stolen token. Fourth, there is no refresh token in the Implicit flow, forcing the application to redirect the user to the authorization server whenever the access token expires, degrading user experience. The Authorization Code flow with PKCE solves all of these problems: tokens are delivered via a secure back-channel POST request, never appear in URLs, and PKCE prevents authorization code interception even without a client secret.

What is PKCE and why is it required?

PKCE (Proof Key for Code Exchange, pronounced "pixy") is an extension to the OAuth 2.0 Authorization Code flow defined in RFC 7636. It was originally designed to protect native mobile applications from authorization code interception attacks, but it is now recommended for all OAuth clients, including server-side web applications. The mechanism works by having the client generate a random string called a code_verifier (between 43 and 128 characters), then computing a code_challenge by applying a SHA-256 hash and Base64url-encoding the result. The client sends the code_challenge with the authorization request. When the authorization server issues the authorization code, it stores the associated challenge. When the client exchanges the code for tokens, it sends the original code_verifier. The server hashes the verifier and compares it to the stored challenge. If they match, the server knows this is the same client that initiated the flow. Even if an attacker intercepts the authorization code (via a malicious app registered with the same custom URL scheme, a compromised redirect URI, or browser history access), they cannot exchange it without the original code_verifier that only the legitimate client possesses. Google, Microsoft, and Auth0 all require or strongly recommend PKCE for public clients.

What is the difference between access tokens and refresh tokens?

Access tokens and refresh tokens serve fundamentally different roles in the OAuth 2.0 security model. An access token is a credential that the client presents to resource servers (APIs) to prove it has been authorized to access specific resources. Access tokens are intentionally short-lived, typically expiring in 5 to 60 minutes, to limit the damage window if a token is compromised. They are sent with every API request in the Authorization header, so they are exposed to network middleware, logging systems, and any service that processes the request. A refresh token, by contrast, is a long-lived credential (days to months) that the client uses exclusively with the authorization server to obtain new access tokens without requiring user interaction. Refresh tokens are never sent to resource servers and are typically stored more securely than access tokens. When an access token expires, the client sends its refresh token to the authorization server's token endpoint and receives a fresh access token. Many implementations use refresh token rotation, where each use of a refresh token invalidates it and returns a new one. This way, if a refresh token is stolen and used by an attacker, the legitimate client's next refresh attempt will fail, alerting the system to the compromise. You can inspect the claims inside JWT-formatted access tokens using our <a href="/jwt">JWT Debugger</a>.