Skip to main content
CodeOath
← All posts

Auth & Security63 min total · 19 parts

OAuth 2.0 and JWT Explained: What Really Happens When You Click "Sign In"

Part 4 of 19 · ~2 min

The Authorization Code Flow, Step by Step

This is the flow behind Priya's web login, and out of everything in this reference, it's the sequence most worth memorizing outright — every other flow below is essentially a variation played on it.

  1. Priya clicks "Sign in with Kestrel" on app.tasklight.dev.
  2. Tasklight's backend redirects her browser to Kestrel's authorization endpoint, carrying its client_id (tasklight-web), a redirect_uri (https://app.tasklight.dev/auth/callback), the scope it's asking for, and a state value — covered properly in the attacks chapter below.
  3. Priya lands on a page Kestrel controls entirely — its own login form, then its own consent screen listing what Tasklight is asking for. Whatever she types into that form goes to Kestrel and stops there; Tasklight's servers sit this step out completely, with no line of code anywhere in Tasklight's stack capable of observing it.
  4. Kestrel sends her browser back to app.tasklight.dev/auth/callback, and tucked into that redirect are two things: a one-time authorization code that's good for well under a minute, and whatever state value Tasklight originally handed it in step 2, unchanged.
  5. Tasklight's backend exchanges that code, together with its own client_secret, for an access token and an ID token, by calling Kestrel directly — server to server, not through Priya's browser — at Kestrel's token endpoint.
  6. Tasklight's backend uses the access token to fetch Priya's profile from Kestrel's People API, and sets its own session cookie so Priya stays logged in to Tasklight going forward, independent of whatever Kestrel does next.
step 1   Priya's browser ---- clicks "Sign in with Kestrel" ---> Tasklight (app.tasklight.dev)
step 2   Priya's browser <--- redirect to Kestrel, carrying ---- Tasklight
                               client_id, redirect_uri, scope, state
step 3   Priya's browser ---- follows redirect, logs in at Kestrel, approves -----> Kestrel
step 4   Priya's browser <--- redirect back to /auth/callback with code + state --- Kestrel
step 5   Tasklight's backend ---- POST code + client_secret (server-to-server) ---> Kestrel
         Tasklight's backend <--- access_token, id_token ------------------------- Kestrel
step 6   Tasklight's backend ---- GET profile, using access_token ---------------> Kestrel
         Priya's browser <---- sets its own session cookie ----------------------- Tasklight

If Priya opened her browser's network tab during all of this, here's what she'd actually be able to see, and it's worth being precise about it because the next chapter's whole argument rests on this exact split. Steps 1 through 4 all happen in requests her browser makes directly, so every one of them is sitting right there in the network tab — including the authorization code itself, visible in the URL of the request in step 4. Step 5 is not. It never touches her browser at all; it's a request Tasklight's backend makes on its own, from server to server, and nothing about it appears anywhere Priya — or anything running in her browser — could inspect. That's not an accident of how this particular diagram happens to be drawn. It's the one design choice the entire flow's security rests on.