Authentication
Authentication answers exactly one question: who are you? It is the first gate at every trust boundary, and it is purely about identity — not about what you’re allowed to do once you’re through (that’s Authorization, the next page). Getting these two confused is the most common conceptual error in security, so hold the line: authentication proves who; authorization decides what.
The three factors
Section titled “The three factors”You can only prove identity with evidence, and all evidence falls into three categories:
SOMETHING YOU KNOW → password, PIN, passphrase (a secret in your head) SOMETHING YOU HAVE → phone, security key, TOTP app (a physical object) SOMETHING YOU ARE → fingerprint, face, voice (a biometric trait)Each factor fails differently, which is the whole point. A password can be guessed or phished but not physically stolen from across the world. A hardware key can be stolen but not phished. A fingerprint can’t be forgotten but also can’t be changed once leaked. Because the failure modes don’t overlap, combining factors is far stronger than strengthening any one of them — which is the entire logic of MFA.
MFA: stacking independent factors
Section titled “MFA: stacking independent factors”Multi-factor authentication requires evidence from two or more different categories. Two passwords are not MFA; password + phone is. The attacker now needs to defeat two unrelated systems at once.
After login: sessions vs. tokens
Section titled “After login: sessions vs. tokens”Proving identity once is not enough — HTTP is stateless, so every subsequent request must somehow say “it’s still me.” There are two dominant strategies, and the choice echoes through your whole architecture.
SESSION (server remembers) TOKEN (client carries proof)───────────────────────── ────────────────────────────login → server stores session login → server signs a token & sends opaque cookie & hands it to clienteach request: cookie → DB lookup each request: token verified by signaturerevoke: delete the row (instant) revoke: hard — token is valid until expirystate lives on the SERVER state lives with the CLIENTA session is a random opaque ID stored in a cookie; the server keeps the real state (who you are, when you logged in) in its own store and looks it up each request. A token (typically a JWT, covered in OAuth & JWT) is self-contained signed proof the client carries and presents.
The trade is sharp. Sessions are trivially revocable — delete the row and the user is logged out this instant — but they require a lookup on every request, which couples authentication to a shared store and complicates horizontal scaling (see Statelessness & Sessions). Tokens are stateless and scale beautifully — any server can verify a signature with no shared state — but you cannot easily un-issue one, so revocation becomes the hard problem. What does statelessness buy us? Effortless scale. What does it cost? The ability to instantly say “no, not anymore.”
Storing passwords: the cardinal rule
Section titled “Storing passwords: the cardinal rule”If you remember one thing from this page: never store a password. Store something derived from it that lets you check a password without ever knowing it. The technique is a one-way hash: a function easy to compute forward and infeasible to reverse.
But a plain hash isn’t enough, for two reasons:
- No salt → rainbow tables. If everyone’s password hashes the same way, an attacker precomputes a
giant table of
hash → passwordonce and cracks your whole database instantly. The fix is a salt: a unique random value stored alongside each hash and mixed in before hashing. Now every user’s hash is unique even if two people chose the same password, and the precomputed table is worthless. - Fast hash → brute force. General-purpose hashes (SHA-256) are designed to be fast, which helps the attacker try billions of guesses per second. Password hashing must be deliberately slow and memory-hard.
This is why you use a purpose-built password hash, not a raw cryptographic one:
bcrypt → battle-tested, tunable "cost" factor (slowness) scrypt → adds memory-hardness (resists custom hardware) argon2 → modern winner; tunable on time AND memory ← prefer this for new systemsThe trade with slow hashing: it buys you a database dump that’s expensive to crack even when (not if) it leaks — but it costs CPU and memory on every single login, so the cost factor must be tuned to be painful for attackers yet tolerable for your servers, and re-tuned upward as hardware improves.
The thread
Section titled “The thread”Authentication is the first thing that happens at a trust boundary, and its job is narrow: convert an anonymous, presumed-hostile request into a named one you can reason about. Everything downstream — authorization, auditing, rate limiting per user — depends on that name being trustworthy. Prove identity with independent factors, carry that proof safely with sessions or tokens, and store the “know” factor in a form that’s useless to a thief. Then, and only then, ask the next question: what is this identity allowed to do? →
Check your understanding
Section titled “Check your understanding”- State the difference between authentication and authorization in one sentence each.
- Name the three factor categories and give one way each can fail.
- Why is “password + PIN” not real multi-factor authentication?
- Sessions vs. tokens: which is easy to revoke, which scales without shared state, and why?
- Explain why a salt defeats rainbow tables and why a slow hash (bcrypt/argon2) defeats brute force.