useradasalt6f1…hashe32…iduseridleLog inada••••••••ada's inbox4289131salt = token_bytes(16)2h = slow_hash(pw, salt)3ok = compare_digest(h, saved)4sid = token_urlsafe(32)id428 913
Back: the server and its two tables, password hashes and sessionsFront: Ada's browser and cookie jar, her phone, and the server's PythonTokens: the password envelope, a hash, a session ID, the cookie, a JWT and a one-time codeAt the back the server stands between its two tables: password hashes (user, salt, hash) and sessions (session ID, user, idle limit). In front: Ada's browser with its cookie jar, her phone, and the server's four lines of Python. The password travels only inside HTTPS and is never stored: the server keeps a salted, slow hash and compares hashes at login. Then a random session ID goes into the session table and, as an HttpOnly, Secure cookie, into the browser's jar; every later request brings it back. The salt in the figure is fixed so you can check the numbers; a real server draws a new random salt for every password, so two people with the same password still get different hashes.

Passwords

  1. Authentication checks who you are: logging in proves you are Ada. Authorization decides what you may do once the server knows that: Ada may read her own messages, not anyone else's. The server makes both decisions, never the browser alone.

Sessions

Tokens and MFA

What happens

;; step 1/11 · authn-authz
authentication   who are you?
                 log in: prove you are ada
authorization    what may you do?
                 ada may open ada's inbox

both are decided on the server: anything the browser
decides on its own can be changed by whoever holds it

slow_hash on the card is Python's hashlib.scrypt with OWASP's minimum settings (n=2**17, r=8, p=1), which needs 128 MiB of memory per try. That cost is small for one login and huge for someone trying billions of guesses. Argon2id is OWASP's first choice where it is available. The salt in the figure is fixed so you can check the numbers; a real server draws a new random salt for every password, so two people with the same password still get different hashes.