auth · Lesson 12 · Capstone

Capstone: Choose It, Then Build It

Eleven lessons gave you the whole map. This one makes it a build. Two skills close the mission: a decision framework for picking which methods to combine for a given app — and a complete, running Express auth app on your machine that wires the pieces together. By the end you'll have logged into something you can read top to bottom and modify with confidence.

🎯 Mission: a mental model of modern auth + the ability to wire it into a real app
The one idea

There is no single "best" auth — there's the right combination for your app's clients, threat model, and team. You choose along a few axes (who are your clients? how sensitive is the data? do you want to own credentials at all?), then assemble from the building blocks you now know. The wiring is short and boring once the decisions are made — and that's the goal: decisions deliberate, implementation unremarkable.

01 The decision framework

Don't start from "which library?" Start from these questions. Each one steers you toward specific lessons.

QuestionIf…Lean toward
Who are your clients?One web app, your domainSession id in an HttpOnly cookie (L1–2)
Mobile / SPA / third-party APIsTokens: short access + rotating refresh (L3, L7)
Do you want to own passwords?No (and users have Google/GitHub)OAuth2 + OIDC — "Sign in with X" (L5–6)
Yes / need first-party accountsPassword (Argon2id) or passwordless (L4, L8)
How sensitive is the data?Low–mediumSingle strong factor + optional TOTP (L10)
High (money, health, admin)Passkeys (L9) or enforced MFA + step-up (L10)
What's your phishing tolerance?Must resist phishingPasskeys — the only phishing-proof option (L9)
Team capacity?Small / don't want to own itA provider (Auth0/Clerk/Cognito) — same concepts, their plumbing
💡 The point of all 12 lessons: you can now read any of those rows Whether you hand-roll or adopt Auth0/Clerk/Cognito, the concepts are identical — a provider just runs the flows you now understand. You learned the model precisely so you can choose a provider wisely and debug it when it misbehaves, instead of cargo-culting a dashboard. That was the mission. Cross-check decisions against OWASP Authentication Cheat Sheet.

02 Three worked examples

🛍️ A SaaS web app

Session cookie (L2) + password (Argon2id) or magic link (L4/L8) + optional TOTP (L10). Add "Sign in with Google" (L6) for convenience. Reset/verify flows per L11. The boring, correct default.

📱 A mobile app + public API

OAuth2 + PKCE (L6, no client secret) → short access token + rotating refresh (L7). API verifies the access token's signature with a pinned alg (L3). No cookies.

🏦 A high-security console

Passkeys (L9, phishing-proof) as primary, backup codes for recovery (L11), step-up re-auth on dangerous actions (L10). Short sessions, "log out everywhere" (L7).

Notice each is just a combination of blocks you've already built and run. There's no twelfth secret technique — mastery is knowing which to combine and why.

03 The reference architecture (the spine, one last time)

Every design in this course shares one skeleton. Internalize it and any auth system is legible:

① LOGIN (varies) password · OAuth/OIDC magic link · OTP · passkey (+ MFA / step-up) ② THE HANDOFF session.userId = id ③ STAY LOGGED IN session cookie OR access+refresh token guards protected routes Swap ① freely; ②–③ barely change. That decoupling is the whole mental model.
The spine you've seen in every lesson: a login method (interchangeable) hands off to a session (stable) that guards your routes. Capstone code below is literally this picture.

04 🎯 Your tangible win (8 min): run a complete auth app

I built a full, working Express auth app on your machine — signup with hashed passwords, login, a CSRF-protected session, a guarded page, and logout. Dependencies are installed and it's smoke-tested.

# in your terminal:
cd ~/projects/learn/public/courses/auth/practice/capstone-app
npm start
# → open http://localhost:3000 and actually sign up + log in
🎯 The win — verified end-to-end on your machine just now
POST /signup (valid CSRF) → 302 /account     ← hashed pw stored, session started
GET  /account (with session) → 🔒 Protected page
GET  /account (no session)   → 302 /login      ← the guard works
POST /signup (bad CSRF)      → 403 Forbidden    ← CSRF defense works
Open server.js — it's ~110 lines and every block is tagged with the lesson it came from: bcrypt.hash (L4), the session() cookie flags (L2), the double-submit checkCsrf (L2), req.session.userId = … (the handoff), requireAuth (the guard), session.regenerate on login (fixation defense, L2), and session.destroy for logout (L7). Nothing in it is new to you. That's the whole point — you can read and modify a real auth system now.

05 A pre-ship checklist (print this)

Cookies (L2)

HttpOnly + Secure (prod) + SameSite=Lax; real session store, not MemoryStore; __Host- prefix.

Passwords (L4)

Argon2id (or bcrypt ≥10); generic login error; rate-limit + lockout; check breached-password lists.

Tokens (L3, L7)

Pin algorithms; short access + rotating refresh; reuse detection; "log out everywhere."

CSRF (L2)

SameSite + a token on state-changing routes (csrf-csrf, not csurf).

OAuth/OIDC (L5–6)

Auth-code + PKCE; state; exact redirect_uri; verify ID tokens (sig + iss/aud/exp).

Lifecycle (L11)

No enumeration; single-use + expiring reset tokens; invalidate sessions on reset; recovery as strong as login.

⚠️ The meta-lesson: prefer boring, vetted plumbing You now understand auth well enough to build it — which is exactly what earns you the right to not hand-roll the dangerous parts. Use express-session, argon2, @simplewebauthn, openid-client, or a managed provider. Your job is correct assembly and sound decisions — not novel cryptography. Understanding ≠ a mandate to DIY.

06 Check yourself

Q1. A startup says "we'll use JWTs for everything because they're modern." Walk them through the decision instead.

Show answer

"Modern" isn't a requirement. Ask: who are the clients? A single web app → session cookies are simpler and instantly revocable (L1–2). Mobile/SPA/public API → then yes, short access + rotating refresh tokens (L3, L7), with reuse detection. JWTs for browser login is the classic over-reach (L1, L3). The format follows from the client and revocation needs, not from fashion. (§01.)

Q2. In the capstone app, why call req.session.regenerate() on login rather than just setting userId on the existing session?

Show answer

Session fixation defense (L2). If an attacker planted a known session id before login, reusing it would let them ride the now-authenticated session. Regenerating issues a fresh id at the moment of privilege elevation, so any pre-login id the attacker knew is useless. (§04.)

Q3. You understand every auth primitive now. Why is hand-rolling your own WebAuthn verification or password hashing still a bad idea?

Show answer

Because correct assembly ≠ reimplementing crypto. The byte-level details (constant-time comparisons, CBOR parsing, signature-counter checks, parameter tuning) are where subtle bugs become vulnerabilities, and vetted libraries have already paid that cost and been audited. Your understanding lets you choose and wire them correctly and debug them — that's the leverage, not DIY crypto. (§05 warning.)

07 🎓 Mission accomplished — and where to go next

Look back at the mission: a durable mental model of modern auth + the ability to wire it into a real app. You have both. You can place any auth system on the spine, name the purpose of every parameter in a "Sign in with Google" redirect, choose a stack for a given app, and read/modify a working Express implementation. The fog is gone.

📌 The whole course in one line Every auth system = an interchangeable login method (password, OAuth/OIDC, magic link, OTP, passkey — optionally multi-factor) that hands off to a session (stateful cookie or stateless rotating token) guarding your routes — built from a small set of primitives: hashing, signing, single-use+expiry, secure cookies, and origin/secret binding.

If you want to keep going (post-capstone topics)

Authorization (authZ)

We mastered authentication. Next axis: permissions — RBAC/ABAC, scopes, policy engines. The "what may you do" half of Lesson 1.

Enterprise SSO

SAML, SCIM provisioning, "Sign in with Okta" — what B2B customers demand.

Machine-to-machine

OAuth client-credentials grant, API keys, service identity, mTLS, DPoP-bound tokens.

💬 This is your call — tell me which thread to pull. Or bring me your real app and we'll design its auth together against the framework in §01. And the standing offer: run the capstone (or any lab) and tell me what you saw — I'll record your first learning record and we'll build the next phase from there. · Back to Lesson 11 · Lesson 1 · Resources.