Authentication

Passwords, sessions, tokens, and rate limits for proving user identity.

In this article

Verifying who the user is. Get this wrong and an attacker can impersonate users, read private data, act on their behalf, and steal money.

Use an auth provider first

But even with a provider, you still need to understand how auth works: that's what this note covers.

1 · Password storage: the evolution

How to store a password correctly went through four stages:

Fig 1Make stolen password hashes expensive to attack
STUDY MODEL
Inspect one part at a timePlaintext
  1. Plaintext

    A database breach directly exposes plaintext passwords such as 12345.

  2. Salt

    A unique random salt prevents precomputed lookup reuse. bcrypt already incorporates a salt; it is not an unsalted-hash example.

  3. Cost

    Argon2id or bcrypt deliberately makes each guess expensive. Tune cost to your system; 400 ms is illustrative, not a universal requirement.

  4. Store and verify

    Store the algorithm’s encoded hash with its parameters and salt. Never use plain MD5 or SHA-256 as a password-storage algorithm.

Use a modern slow password hash with a unique salt. A salt alone does not make a fast hash suitable.

How to read this model

A password inspection press with separate salt and cost controls. The object is a teaching analogy. Inspecting a part highlights its role; it does not execute or simulate the software. Cabinet trays are records, workpieces are data, and latches are checks. Unless an explanation states a quantity, compartments and sample workpieces do not denote data counts. Part dimensions are not a quantitative scale.

Why each stage fails (and how the next fixes it)

Stage 1: plaintext. Databases get breached every day. If you store the password as-is, the attacker gets every user's real password. And ~70% of users reuse passwords across sites, so one breach cascades.

Stage 2: hash. A hash is a one-way, fixed-length output. Same input → same output. You can't reverse it. So you store hash(password).

But attackers built rainbow tables: precomputed maps of common password → hash. If your hash("12345") matches their table, they reverse it instantly.

Stage 3: salt. Add a random per-user string before hashing: hash(password + salt). Store the salt too. Now two users with the same password have different hashes, and rainbow tables return zero matches.

Stage 4: slow hash. GPUs can compute billions of SHA-256 hashes per second. So an attacker with your leaked hashes + salts can still brute force common passwords offline. The fix is a slow hash (Argon2id, bcrypt) with a cost factor you tune: e.g. 400 ms per hash. A real user won't notice 400 ms on login; an attacker goes from billions of guesses/second to a handful.

2 · Sessions (stateful auth)

Once a user logs in, you can't ask for the password on every request. You create a session:

Fig 2A cookie points to server-side state
STUDY MODEL
Inspect one part at a timeAuthenticate
  1. Authenticate

    Check the supplied email and password.

  2. Create session

    Generate an unpredictable session ID with at least 128 bits of entropy; the example allows 128–256 bits.

  3. Store and set cookie

    Store the ID and metadata in a database or Redis. Set appropriate HttpOnly, Secure, and SameSite cookie flags.

  4. Look up on requests

    The browser sends the cookie; the server looks up the session to establish identity. Delete or expire state to revoke it.

The cookie carries an unguessable identifier; the server owns session state and revocation.

How to read this model

An opaque-key dispenser beside a session archive. The object is a teaching analogy. Inspecting a part highlights its role; it does not execute or simulate the software. Cabinet trays are records, workpieces are data, and latches are checks. Unless an explanation states a quantity, compartments and sample workpieces do not denote data counts. Part dimensions are not a quantitative scale.

Flag What it does
HttpOnly JavaScript cannot read the cookie → XSS can't steal the session
Secure Cookie sent only over HTTPS → not sniffable on public Wi-Fi
SameSite Strict/Lax → not sent on cross-site requests → blocks CSRF

3 · JWT (stateless auth)

A JWT is the whole session data, handed to the client. The client sends it back on every request; the server stores nothing.

Fig 3A signature protects integrity, not secrecy
STUDY MODEL
Inspect one part at a timeHeader
  1. Header

    The header names the algorithm, illustrated by HS256. JWT segments use base64url encoding.

  2. Payload

    Claims such as sub, iat, and role are encoded, not encrypted.

  3. Signature

    For HS256, compute the HMAC over header.payload with the secret. Verify the expected algorithm, signature, issuer, audience, and time claims.

A JWT payload is readable. Never put secrets in it just because it is signed.

How to read this model

A three-part message holder beside a signing die. The object is a teaching analogy. Inspecting a part highlights its role; it does not execute or simulate the software. Cabinet trays are records, workpieces are data, and latches are checks. Unless an explanation states a quantity, compartments and sample workpieces do not denote data counts. Part dimensions are not a quantitative scale.

The server signs header.payload with a secret key. On each request it re-verifies the signature: if the payload was modified, verification fails and the server rejects it.

JWT trade-offs (the security angle)

Concern Problem Mitigation
Revocation is hard Can't delete a token from the client blacklist tokens; short expiry + refresh tokens
Payload is readable base64, not encrypted: anyone can decode it never store secrets in claims
Storage localStorage is XSS-stealable use an HttpOnly cookie
Fig 4Rotate refresh tokens and detect reuse
STUDY MODEL
Inspect one part at a timeLogin
  1. Login

    Issue an access token and refresh token A. The original example uses a 15-minute access lifetime and a 7-day refresh lifetime.

  2. Access

    Use the access token for API calls while it remains valid.

  3. Rotate

    An accepted refresh consumes A and returns a replacement refresh token B plus a fresh access token.

  4. Reused A

    Reject reuse of the consumed token and apply the system’s token-family revocation policy. Rotation needs server-side tracking.

Refresh-token reuse is a signal to revoke the affected token family and reauthenticate.

How to read this model

A single-use credential magazine with a revocation latch. The object is a teaching analogy. Inspecting a part highlights its role; it does not execute or simulate the software. Cabinet trays are records, workpieces are data, and latches are checks. Unless an explanation states a quantity, compartments and sample workpieces do not denote data counts. Part dimensions are not a quantitative scale.

4 · Rate limiting: mandatory on auth

Without rate limiting, an attacker can hammer your login endpoint with millions of guesses, or crash the server with raw volume. Layer it:

Fig 5Combine independent abuse limits
STUDY MODEL
Inspect one part at a timePer IP
  1. Per IP

    The example allows 10 attempts per minute per IP.

  2. Per account

    The example locks after 5 failures in 15 minutes. This can catch attempts spread over rotated IPs.

  3. Global

    A system-wide limit of N attempts per minute protects total capacity.

  4. Policy

    Authentication endpoints need deliberate limits, recovery rules, and protection against lockout abuse.

Limits at different scopes catch different attack patterns. These numbers are example policies.

How to read this model

Three independently operated admission latches. The object is a teaching analogy. Inspecting a part highlights its role; it does not execute or simulate the software. Cabinet trays are records, workpieces are data, and latches are checks. Unless an explanation states a quantity, compartments and sample workpieces do not denote data counts. Part dimensions are not a quantitative scale.

Terms: GLOSSARY · Related: cache · communication · Next: authorization · Up: security mindset

Keep track of your reading.

Your reading progress stays in this browser.