Authentication
API keys, JWT tokens, OAuth2 flows.
Authentication answers "who are you?"; authorization answers "what can you do?". The tooling — API keys, JWTs, OAuth2 — exists on a spectrum from "trivial" to "I need to draw a diagram." Picking the right level for the job is half the battle.
The big idea
There are essentially three layers:
Each layer solves a problem the layer below didn't. Don't reach up the stack until you have the problem the next layer solves.
API keys: the simplest thing that works
An API key is a long random string the client sends on every request. The server looks it up, finds the account, and proceeds. That's it.
GET /v1/orders HTTP/1.1
Host: api.example.com
Authorization: Bearer sk_live_4eC39Hq…- Use for machine-to-machine access where one party owns the secret.
- Hash keys at rest like passwords; never log them.
- Make them rotatable; show the key once at creation and the prefix forever after.
- Use them for end-users via a browser. The browser will leak them.
- Embed them in mobile apps without server-side scoping.
- Send them as URL query parameters — they end up in logs and proxies.
JWT: signed, self-describing tokens
A JSON Web Token is three base64url-encoded strings: header, payload, signature.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 # header
.eyJzdWIiOiI0MiIsImV4cCI6MTczMzAwMDAwMH0 # payload (claims)
.dBjftJeZ4CVP-mB92K27uhbUJU1p1r… # signatureThe server signs the payload with a secret (HMAC) or a private key (RSA/EC). It can later verify the token without a database lookup: stateless auth. The trade-off is that you can't easily revoke a JWT before it expires.
- 1. POST /login (creds)
- 2. access_token (JWT, 15 min)
- 3. GET /me + Bearer JWT
- 4. verify signature → 200no DB call
OAuth2: delegating access to a third party
When a user wants to let an app (Slack, Notion, your bot) act on their behalf at another service (Google, GitHub) — without giving up their password — that's OAuth2.
The flow you should know by heart is Authorization Code with PKCE:
- 1. Redirect to provider w/ PKCE challenge
- 2. Login + consent
- 3. Redirect back to app w/ code
- 4. Code arrives in callback URL
- 5. POST /token (code + PKCE verifier)
- 6. access_token + refresh_token
- 7. API calls w/ Bearer access_token
Other grant types exist (client_credentials for machine-to-machine, device_code for
TVs, etc.) — learn them when you need them. Avoid implicit and password grants, both
are deprecated for good reasons.
Sessions are still fine
For server-rendered web apps that own their frontend, plain session cookies beat JWTs:
they're easy to revoke, the browser handles them, and HttpOnly + Secure + SameSite
defends against the common attacks. Use JWTs when you genuinely need stateless verification
across services.
Key takeaways
- API keys for machine-to-machine; never expose them to a browser.
- JWTs are stateless and convenient, with revocation as the main pitfall.
- Use OAuth2 (Authorization Code + PKCE) for third-party delegation.
- Session cookies are still the simplest correct answer for many web apps.
- Authentication and authorization are different problems — keep them separate.
Checkpoint questions
Use these to test whether the lesson is clear enough to explain without rereading.
- 1When would you choose API keys, sessions, JWTs, or OAuth2?
- 2What must a server verify before trusting a JWT?
- 3Why does Authorization Code with PKCE exist, and what problem does it solve?
- 4How should authentication failures differ from authorization failures?
References
External resources for going deeper after the lesson above.