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 15 of 19 · ~2 min

OpenID Connect: The Identity Layer on Top of OAuth

Go back to the very first chapter of this reference: OAuth answers what a client is allowed to do, and pointedly refuses to answer who's asking. OIDC is the layer that fills that hole in, standardizing exactly how a client finds out, in a way it can actually verify rather than just take on faith. Three concrete pieces make that possible, and Priya's login used every one of them.

Requesting the openid scope in step 2 is the signal that flips this on at all — without it, Kestrel treats the request as ordinary OAuth and never issues an ID token in the first place. That ID token, once issued, is where the actual identity claims live, and — this is worth pausing on — it's checked with nothing new: the same signature, exp, nbf, iss, and aud verification from the validation chapter earlier applies to it exactly as written, because underneath the label, an ID token is just another JWT. And rather than making every client hardcode Kestrel's specific endpoint URLs, Kestrel publishes a discovery document at https://id.kestrel.example/.well-known/openid-configuration listing all of them — its authorization endpoint, its token endpoint, its JWKS location, and its UserInfo endpoint, a separate place a client can query directly, using the access token, for whatever profile fields weren't already baked into the ID token itself. Any OIDC-aware client can find every one of those by fetching a single well-known URL, instead of needing provider-specific setup for Kestrel and a different setup entirely for the next identity provider it integrates.

Concretely, here's what actually lands in Tasklight's backend at step 5 of the code flow, decoded — the artifact this entire chapter has been building toward:

{
  "iss": "https://id.kestrel.example",
  "sub": "kes_9f3a2b",
  "aud": "tasklight-web",
  "email": "priya@example.com",
  "email_verified": true,
  "name": "Priya Nair",
  "iat": 1732550400,
  "exp": 1732554000
}

It's worth remembering what integrating logins looked like before this was standardized: every identity provider answered "who logged in" its own way, and a client working with three of them maintained three separate, incompatible pieces of glue code, one per provider's particular quirks. A developer adding Kestrel support to some other product today writes against the same discovery document, the same token shape, the same claim names this chapter just walked through — whether that product also happens to support two other identity providers or none at all.