In revision.
Crisp5 min readGo deeper →

OAuth 2 flows

OAuth 2 is delegated authorization: user grants a third-party app limited access to their account on another service, without sharing the password.

OAuth 2 is authorization, not authentication. It answers "can this app act on the user's behalf at this service" not "who is the user." For authentication you layer OpenID Connect on top of OAuth, which adds an ID token (a JWT identifying the user).

Four parties.

  • Resource owner: the user.
  • Client: the third-party app (your Next.js site).
  • Authorization server: where the user logs in (Google, GitHub).
  • Resource server: the API holding user data (Google Calendar, GitHub API).

The canonical flow is Authorization Code, optionally with PKCE for public clients.

Authorization code flow with PKCE. The code is a short-lived one-time credential exchanged for tokens.

Why the code instead of just returning the token directly? Because the code goes through the browser URL bar (which can leak to logs and referrers), but the token exchange happens server-to-server over TLS. The code alone is useless without the client_secret (server-side) or PKCE code_verifier (SPA/mobile).

PKCE (Proof Key for Code Exchange, RFC 7636). For apps that cannot keep a client_secret safe (SPAs, mobile), PKCE replaces it. The client generates a random code_verifier, hashes it (code_challenge = SHA256(code_verifier)), sends the challenge with the initial request. When exchanging the code for a token, it sends the verifier. The auth server checks SHA256(verifier) == challenge. Prevents code interception attacks.

The four flow types and when to use each.

  • Authorization Code with client_secret: server-side web app. Most secure.
  • Authorization Code with PKCE: SPA or mobile app. The new standard.
  • Client Credentials: machine-to-machine, no user involved.
  • Device Code: TVs, CLIs without a browser.
  • Implicit and Password: deprecated. Do not use.

For "Login with Google," you actually want OpenID Connect (OIDC). Same flow, plus an id_token (a JWT signed by Google with the user's email and name) so you do not need a separate userinfo call.

Learn more