← Back to all articles

OAuth2 Authorization Code: What Third-Party Login Does

SecurityBeginner

Core idea

OAuth2 solves delegated authorization: you let an app act on your behalf without handing it your password. The app gets a scoped access token, not your credentials.

Authorization-code flow

  1. The app redirects the browser to the authorization server with client_id and a redirect URI;
  2. You log in there and consent;
  3. The server redirects back with a one-time authorization code;
  4. The app exchanges the code plus client_secret for an access token (server-side, never in the browser).

Two tokens

TokenUseLifetime
access tokenCall APIsShort
refresh tokenGet new access tokensLong

Why PKCE

Mobile and SPA apps cannot keep client_secret safe. PKCE replaces the secret with a one-time challenge: an attacker who intercepts the code still cannot trade it without the challenge.

Real-world cases: three authorization-code mistakes

  1. Storing access_token in the frontend: one XSS steals it. The steadier pattern is for the frontend to hold only the code, with the backend exchanging it — or PKCE for public clients.
  2. Not validating state on the callback: an attacker can craft a callback that binds the victim's account to their own authorization (login CSRF). state must be generated once and verified against the session.
  3. Wildcard redirect_uri: an open redirect can deliver the authorization code to an attacker's domain. Callback URLs must be an exact, per-entry allowlist — no prefix or wildcard matching.

FAQ

Why exchange the code for a token at all? The code appears only briefly in the frontend and must be exchanged by the backend with client_secret, keeping tokens out of browser history and logs. What does PKCE solve? It lets public clients that cannot keep a client_secret (mobile apps, SPAs) use the authorization-code flow safely. Is OAuth2 an authentication protocol? It handles authorization; authentication layers on OpenID Connect's id_token. Where should a refresh_token live? Server-side only, with rotation and revocation.

Operating the authorization server and tokens

Once OAuth2 is integrated, the long-term cost sits in token and client management:

  1. Record every client registration: callback URLs, secrets and owners, with secret rotation and an overlap window so rotation is not an outage;
  2. Tiered token lifetimes: short access tokens (minutes) and longer refresh tokens that can be revoked, rotated on each refresh to shrink the theft window;
  3. Minimal scopes: request only what is needed, and let users review and revoke authorised apps at any time;
  4. Anomaly detection: the same refresh token used in two places, or a burst of exchanges, may signal compromise — alert and support one-click revocation;
  5. Logout must cascade: revoke tokens on logout instead of only clearing frontend storage, or the token stays valid.

Keep authorization codes short-lived (30–60 seconds) and single-use; a reused code should be treated as a leak and invalidate all tokens from that grant.

Connecting to business permissions

  1. Separate identity from permission: tokens answer who you are and what you may reach; which records you can change is still a business decision. Do not judge them in one place.
  2. Authorise at the resource: every resource endpoint must check the caller's right to that resource rather than trusting a valid token, or privilege bugs cluster on a few endpoints.
  3. Keep volatile permissions out of tokens: embedding permissions delays changes until expiry; systems that adjust access often should query at runtime or use shorter token lifetimes.
  4. Audit against the token: record the calling identity on all significant operations so you can trace which application performed what.
  5. Revocation must cascade: when a user revokes a third-party app, invalidate its tokens, not just the stored state.

With clear boundaries, the protocol handles admission and your system handles capability — and privilege investigations get much easier.