Recipe

OAuth 2.0 flow diagram explainer

Visual breakdown of the authorization code grant with PKCE — the industry standard for server-side web apps.

1
UserClicks "Sign in with Provider"

Browser navigates to /api/auth/login?provider=github with a generated state param and code_challenge.

2
BrowserRedirects to Provider's authorize endpoint

GET /authorize?response_type=code&client_id=...&redirect_uri=...&scope=...&state=...&code_challenge=...

3
ProviderAuthenticates user, prompts consent

If user is not logged in, Provider shows its own login screen. Then asks for scope approval.

4
ProviderRedirects back with authorization code

302 → /api/auth/callback?code=AUTH_CODE&state=... — code is single-use, expires in ~60s.

5
ServerExchanges code for tokens

POST /token with grant_type=authorization_code, code, redirect_uri, and code_verifier (PKCE).

6
ProviderReturns access_token + refresh_token

JSON response: { access_token, token_type, expires_in, refresh_token, scope }. Server stores refresh_token encrypted.

7
ServerFetches user profile, creates session

GET /user with Authorization: Bearer access_token. Server upserts user record, issues session cookie.

8
BrowserReceives session cookie, redirected to dashboard

Set-Cookie: session_id=...; HttpOnly; Secure; SameSite=Lax. 302 → /dashboard. User is now authenticated.

PKCE note: Even though this is a server-side flow, PKCE prevents authorization code interception attacks. The code_verifier is generated per-login and never leaves the server until the token exchange.