Module 14 / 20 · Phase C — Scale & Reliability · 45 min

Auth 101:
OAuth & JWT.

"Sign in with Google" is one of the most-clicked buttons on the internet. Behind it: a delicate seven-step dance involving four parties, two redirects, and a signed token. Time to look at what's actually happening.

// What you'll know by the end

  • Authentication vs authorization (yes, they're different)
  • The four parties in any OAuth flow
  • What "Sign in with Google" actually does
  • What's inside a JWT and what's not
§ 01 — A small password problem

Every site asks
for a password.

You sign up for a new app. It wants a password. You're tired, so you reuse the one you've been using since college. Now imagine you do this every week for a year. One of those sites gets breached. Suddenly attackers have one password — and they try it on Gmail, your bank, Amazon, Slack, everywhere. This is exactly how 80% of "hacked" accounts get hacked. Not a technical attack. Not a clever exploit. Just password reuse, harvested from one weak site.

// TWO WORLDS · SAME APP NEEDING TO KNOW WHO YOU ARE
// THE OLD WAY
Build your own login

App stores your email + hashed_password. Every site has its own copy of your credentials. Every site can leak them. Every site can be breached. Every site needs to handle password resets, 2FA, suspicious-login emails. Massive engineering surface area for a problem nobody wants to own.

// THE NEW WAY
Delegate to Google

App says "I don't store your password. Go log in with Google, then tell me you're authentic." Google handles the actual login (it's their job). Google issues a token saying "yes, this is Alice." Your app trusts Google's word. One password, one place that handles security well.

That second approach — delegated identity — is what OAuth 2.0 formalizes. It's the protocol behind "Sign in with Google/Apple/GitHub/Facebook," and it's also the protocol that powers the much subtler case where one app needs to do something on another app's behalf (your calendar app reading your email, a code editor pushing to your GitHub). It's everywhere, and it's worth understanding properly because the details are where bugs hide.

§ 02 — Two words people conflate

"AuthN" and
"authZ" are different.

Before going further: there's a distinction that catches everyone. Authentication (often abbreviated authN) and authorization (authZ) sound nearly identical and get used interchangeably. They're not the same. Mixing them up causes some of the most embarrassing security bugs in the industry, so let's get it straight.

// AUTHENTICATION vs AUTHORIZATION

// AUTHN

Authentication

"Who are you?"
Proving identity. The login step. Determining that the person making this request is, in fact, Alice. Usually a password, fingerprint, or a token vouching for past authentication.
User: "I'm Alice. Password: hunter2"
Server: "✓ confirmed, you're Alice"
// AUTHZ

Authorization

"What can you do?"
Deciding access. Now that we know it's Alice, can she view this document? Edit billing? Delete the production database? Comes after authentication and uses the identity to look up permissions.
Alice → DELETE /users/42
Server: "Alice is an admin: ✓ allowed"

The mnemonic that sticks: AuthN is the bouncer at the door, authZ is the bouncer at each VIP section. Or in code terms: authN sets req.user = Alice; authZ checks req.user.can('delete:user', target). The bugs come from forgetting the second one — you authenticated the user, but then you forgot to ask whether they're allowed to do this specific thing. Every "I logged in and saw someone else's account" incident is an authZ bug, not an authN bug.

Authentication says "I know who you are." Authorization says "and here's what that means you can do."

OAuth, despite the name suggesting "auth" in the singular, is fundamentally about authorization — getting permission to do things on behalf of a user. The fact that it also gets used for authentication (via the related OpenID Connect standard layered on top) is a historical accident that confuses everyone for their first year of working with it. Don't worry — once you've seen the dance once, it makes sense.

§ 03 — The four parties

In every OAuth
flow, four players.

OAuth involves a small cast. Once you know who they are and what each one wants, the dance becomes legible. The names sound abstract, but every flow has the same four actors with the same roles. Whether you're logging in with Google, GitHub, or your own internal corporate SSO, this cast doesn't change.

// THE CAST · WHO'S WHO IN OAUTH

👤 RESOURCE OWNER aka "the user" You. Alice. Owns the data being accessed; grants consent. 📱 CLIENT aka "your app" SystemDesign The app that wants to access user data. 🔐 AUTH SERVER aka "the identity provider" Google / Apple / GitHub Authenticates user; issues tokens after consent. 📊 RESOURCE SERVER aka "the API" Google's APIs Holds the actual data; checks token on each call. In "Sign in with Google": you are RO, your app is the Client, Google is both Auth and Resource Server.

Often the Auth Server and Resource Server are run by the same company — Google handles both authentication and the APIs you'd later call. But conceptually they're distinct: one job is "verify identity and grant tokens," the other is "serve the actual data when a token shows up." Keeping them separate in your head makes the dance below much clearer.

§ 04 — The OAuth dance · step-by-step lab

Now walk through
"Sign in with Google."

Below: every step of the OAuth authorization code flow, one click at a time. You'll see the arrows fly between the four parties, with a detail panel showing exactly what's being sent — URLs, parameters, tokens. By the end you'll understand why there's a redirect dance instead of just "give me the password."

OAUTH_DANCE.SIM // m.14 lab
USER browser YOUR APP SystemDesign GOOGLE AUTH accounts.google.com GOOGLE API www.googleapis.com
PRESS NEXT TO BEGIN
The OAuth dance
Ten steps, four parties. The user clicks "Sign in with Google" and through a careful sequence of redirects ends up logged into your app — without your app ever seeing their password. Press Next step to begin.
// Flow progress
§ 05 — Inside a JWT

A token
you can read.

When step 6 of the dance finished, Google handed your app an access token. In modern OAuth setups, that token is usually a JWT — JSON Web Token — pronounced "jot." It looks like a random string but it's actually three base64-encoded chunks separated by dots, and you can decode it yourself with no special tools. Here's a real one:

// A REAL JWT · COLOR-CODED BY PART

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMTIyMzM0NDU1IiwibmFtZSI6IkFsaWNlIENoZW4iLCJlbWFpbCI6ImFsaWNlQGV4YW1wbGUuY29tIiwiaWF0IjoxNzA0MDY3MjAwLCJleHAiOjE3MDQwNzA4MDB9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cP7M8VPnv8aJ3F-_xLdY9Hpz3lT-eS2bF
// PART 1 — HEADER
What kind of token
{
  "alg": "RS256",
  "typ": "JWT"
}
Algorithm used to sign + token type. RS256 = RSA signature with SHA-256.
// PART 2 — PAYLOAD
The claims (data)
{
  "sub": "1122334455",
  "name": "Alice Chen",
  "email": "alice@example.com",
  "iat": 1704067200,
  "exp": 1704070800
}
Subject (user ID), name, email, issued-at, expires. Visible to anyone with the token.
// PART 3 — SIGNATURE
The proof of integrity
HMACSHA256(
  base64url(header) + "." +
  base64url(payload),
  SECRET_KEY
)
Cryptographic signature. Proves the token came from Google and wasn't modified. Anyone can read the JWT; only the issuer can produce a valid one.

That third part is the magic. Anyone can look at the header and payload (they're just base64). But to produce a valid signature, you need the private key. So when your app receives a JWT, it can verify the signature using Google's public key — and if it checks out, your app knows two things: this token came from Google (not an attacker), and the claims inside haven't been tampered with. Validation happens locally, no API call needed.

Anyone can read a JWT. Only the issuer can make one that verifies.

The standard payload fields have abbreviated names — sub for subject (user ID), iat for issued-at, exp for expiry, iss for issuer, aud for audience. There are about a dozen of these "registered claims." You can also add your own custom claims — email, name, role, whatever your app needs. Just keep in mind they're visible: don't put secrets in a JWT.

// GOTCHA 1

JWTs are signed, not encrypted

Anyone with the token can decode and read the payload. Never put passwords, internal IDs, or secret data in a JWT. If you need encryption, look at JWE — but most production systems just keep claims minimal.

// GOTCHA 2

Hard to revoke before expiry

JWTs are stateless — that's the point. But it also means once issued, you can't "log someone out" until the token expires. The workarounds (short expiries + refresh tokens, or a revocation list) add complexity.

// GOTCHA 3

Always validate the signature

Some library defaults will accept tokens with alg: "none" (no signature). Reject those. Always specify the expected algorithm and use a library that validates by default.

// GOTCHA 4

Tokens get bigger with claims

Every claim you add increases the token size. Tokens are sent on every request (in the Authorization header), so a bloated JWT = bigger requests for the life of the session. Keep them lean.

§ 06 — Eight words for the auth layer

Vocabulary,
for the identity dance.

You'll meet these in every login flow, every API doc, and every security postmortem. Lock them in.

AuthN / AuthZ
/ˈɔːθ-ɛn · ˈɔːθ-zee/
Authentication ("who are you?") vs Authorization ("what can you do?"). Distinct concerns; bugs come from conflating them.
OAuth 2.0
/oʊˈɔːθ/
The standard protocol for delegated authorization. Lets an app act on a user's behalf without holding their password. The protocol behind "Sign in with..."
JWT
/ˈdʒɒt/ ("jot")
JSON Web Token. A signed token containing claims (user ID, role, expiry). Readable by anyone; only the issuer can create a valid one. Verifiable locally.
Access Token
/ˈæksɛs/
A short-lived credential (often a JWT) that grants access to APIs. Sent on every API request, usually in the Authorization: Bearer <token> header.
Refresh Token
/ˈriːfrɛʃ/
A long-lived credential used to get new access tokens without re-prompting the user. Stored securely. Lets you have short-lived access tokens + long-lived sessions.
Scope
/skoʊp/
The specific permissions an access token grants — read:email, write:repos. Limits what the app can do even with a valid token. Principle of least privilege.
Claim
/kleɪm/
A field in a JWT payload (sub, name, exp, iat). Each claim asserts something about the user or the token itself.
OpenID Connect
/ˈoʊpən aɪˈdiː/
A thin authentication layer built on top of OAuth 2.0. Adds an id_token with user identity info. What "Sign in with Google" actually uses.
§ 07 — Knowledge check

Five questions.
Trust the signature.

Test the auth intuition you just built. Click an answer; the explanation lands immediately.

QUESTION 1 OF 5
Loading question...
Score: 0 / 5
5 / 5

Verified.

The dance and the token are no longer mysterious. Next: how you tell if any of this is actually working — logs and metrics.

§ 08 — The recap

Three ideas to
carry forward.

Auth touches every system. These three carry through every architecture you'll work on.

i

AuthN ≠ AuthZ

Authentication answers "who." Authorization answers "what they can do." Forget the second one and you ship an account-takeover bug.

ii

OAuth = delegation

Your app never sees the user's password. It gets a scoped token from the identity provider. One password, one place that handles security.

iii

JWTs are readable + provable

Anyone can decode them. Only the issuer can make them. Don't put secrets in. Always validate the signature.

↓ UP NEXT

M.15 — Logging
& metrics.

You've built a system that's distributed, cached, load-balanced, and auth'd. There's just one problem: you can't see it. When something breaks at 3 AM, how do you know what's wrong? Time to look at how production systems make themselves observable.

Continue to Module 15 →