Security · AuthN & AuthZ

AuthN & AuthZ

Who are you, and what may you do — passwords done right, sessions vs tokens, OAuth without the hand-waving.

Security Basics → Interview
01

Two Different Questions

Authentication (authn) verifies identity: who are you? Authorization (authz) verifies permission: may you do this? They fail differently — a broken login is authn; reading someone else’s invoice by changing an ID in the URL is authz (and it’s the more common bug). HTTP even splits the status codes: 401 unauthenticated, 403 unauthorized.

Factors of authentication: something you know (password), have (phone, hardware key), are (biometrics). MFA = two different factors — two passwords is not MFA.
02

Storing Passwords — the Only Right Way

Never store passwords, encrypted or otherwise — store a slow, salted hash. The salt (random, per-user, stored beside the hash) kills rainbow tables and makes identical passwords hash differently. The slowness (bcrypt, scrypt, argon2 — tunable cost) turns a billion-guesses-per-second GPU into thousands.

Python — argon2 / bcrypt pattern
from argon2 import PasswordHasher

ph = PasswordHasher()            # sane defaults: memory-hard, salted
digest = ph.hash("correct horse battery staple")
# store digest; salt & params live inside the string

ph.verify(digest, attempt)       # raises on mismatch
MD5/SHA-256 for passwords is the classic breach headline: they’re designed to be fast, which is exactly what a cracker wants. Add rate limiting and breach-password denylists; consider pepper (server-side secret) for depth.
03

Sessions vs JWT

Server sessions
  • Opaque ID in an httpOnly cookie
  • State server-side — instant revocation
  • Needs shared session store to scale (Redis)
  • Default choice for first-party web apps
JWT tokens
  • Signed claims live in the token itself
  • Stateless — any instance verifies locally
  • Revocation before expiry needs a denylist
  • Fits APIs, microservices, mobile clients

Cookie flags are non-negotiable either way: httpOnly (JS can’t read it — blunts XSS token theft), Secure (HTTPS only), SameSite=Lax/Strict (blunts CSRF). For JWTs: short expiry + refresh tokens, verify the algorithm server-side (reject alg: none), and never put secrets in the payload — it’s only signed, not encrypted.

04

OAuth 2.0 & OIDC — Delegated Access

OAuth answers: how does app A get limited access to your data in service B without ever seeing your B password? The authorization-code flow: app redirects you to the provider → you log in and consent there → provider redirects back with a one-time code → app’s backend exchanges code + client secret for an access token, scoped and expiring.

Browser Your App Provider(Google, GitHub) 1 · redirect: login + consent at provider 2 · redirect back with one-time code 3 · backend: code + secret 4 · scoped access token

OIDC is a thin identity layer on top: an id_token (JWT) asserting who logged in — OAuth is for access, OIDC is for login. For authorization inside your app, start with RBAC (roles → permissions) and check permissions server-side on every request — never trust the client’s word for its role.

05

Interview Questions

401 vs 403 — and which layer failed?

401: we don’t know who you are — authentication failed, retry with credentials. 403: we know exactly who you are and the answer is no — authorization denied. Different bugs, different fixes.

Why bcrypt/argon2 over SHA-256 for passwords?

SHA-256 is built for speed — GPUs try billions per second. bcrypt/scrypt/argon2 are deliberately slow and (argon2/scrypt) memory-hard, with tunable cost, collapsing offline cracking rates. Plus built-in per-user salts.

How would you revoke a JWT before it expires?

You can’t un-sign it — so keep expiry short with refresh tokens, and maintain a server-side denylist of revoked token IDs (jti) checked on each request. Note that this reintroduces state — the honest trade-off interviewers want acknowledged.

Walk through the OAuth authorization-code flow — why the code step?

Redirect → consent at provider → code back via browser → backend exchanges code + client secret for tokens. The code exists because the browser redirect is observable: the code alone is useless without the client secret (or PKCE verifier for public clients), so an intercepted redirect leaks nothing usable.

Quick Quiz

1. Changing /invoice/17 to /invoice/18 and seeing another user’s data is broken…
2. A salt primarily defeats…
3. Which cookie flag stops JavaScript from reading the session cookie?
4. JWT payloads are…
5. In OAuth, your app exchanges the authorization code for tokens using…