OAuth 2 Authorization Code Flow Explained Clearly
Understand OAuth 2 authorization code flow, PKCE, redirect URIs, scopes, tokens, consent, security checks, and common integration mistakes.
OAuth is about delegated access
OAuth 2 lets a user grant an application limited access to resources without giving that application the user's password. A calendar app can ask for calendar access, a reporting tool can ask for read-only analytics access, and a mobile app can sign in through an identity provider. The authorization code flow is the standard flow for many secure web and mobile integrations.
The flow works by sending the user to an authorization server, getting their consent or login, returning a short-lived code to the client, and exchanging that code for tokens through a back-channel request. This separates user interaction from token issuance and gives the authorization server a controlled place to enforce policy.
PKCE protects public clients
PKCE adds a code verifier and code challenge so an intercepted authorization code is not enough to get tokens. It is essential for mobile apps and single-page apps, and it is also a sensible default for many modern OAuth clients. Without PKCE, a stolen code can be more dangerous, especially when the client cannot safely keep a secret.
Redirect URIs must be exact. Loose redirect matching creates room for attackers to steal authorization codes. Register allowed redirect URIs, reject unexpected values, and avoid wildcard patterns unless there is a carefully reviewed reason. A redirect URI is not just a routing detail. It is part of the security boundary.
- Use authorization code flow with PKCE for modern user-facing clients.
- Keep scopes narrow and understandable.
- Validate state parameters to reduce CSRF risk.
- Use exact redirect URI matching.
Scopes should match user intent
Scopes define what the client is asking to do. Broad scopes may be convenient for developers, but they can make consent screens untrustworthy. A user should understand why an app needs access. A partner integration should not receive write permission when it only needs to read reports.
For global products, scope naming and consent language should be clear to non-specialists. Avoid internal jargon. Explain what access means in practical terms. If access includes sensitive data, say so. Consent is only meaningful when users and administrators can understand it.
Tokens need careful handling
Access tokens should be short-lived and sent only to the resource servers they are meant for. Refresh tokens should be protected more strongly because they can mint new access tokens. Rotation, reuse detection, and device/session visibility can reduce risk. Server-side web apps can keep tokens on the server, while public clients need platform-appropriate storage and stricter lifetime choices.
OAuth bugs often come from incomplete validation: missing state checks, weak redirect matching, accepting tokens meant for another client, or treating an identity token as proof of API authorization. Follow the flow precisely and use mature libraries instead of hand-rolling every detail.
Make integrations observable
Track authorization success, token exchange failures, invalid redirect attempts, scope usage, refresh failures, and revoked grants. These signals help support teams debug partner issues and help security teams detect abuse. OAuth is not just a login screen. It is a delegated access system that needs ongoing visibility.