Authentication: passwords, factors and tokens
Password storage that survives a database dump, why TOTP is not SMS, the real cost of JWTs, and why OAuth is delegation rather than login.
You already know the difference between hashing and encryption: a hash cannot be turned back into its input, encryption can. That is the whole reason a site stores a hash of your password rather than the password itself. What that lesson could not cover is the part that decides whether the stored hash actually protects anyone in practice. This lesson is about that part, and about everything that happens around the password field. Everything above assumes the attacker is outside. The uncomfortable part of this lesson is that the most common way in is a valid account used by someone who should not have it, or a valid password typed into a page that was not the real one. That is also why the controls that look unglamorous, such as a password manager, a second factor and a short session lifetime, do more work in practice than any clever cryptographic design.
SHA-256 is the wrong tool for passwords, and not because it is weak. It is weak here because it is fast. A modern graphics card tries on the order of 10^11 SHA-256 hashes per second, so every possible eight-character password falls in seconds. A password hash needs the opposite property: it must be slow on purpose, and it must be slow in a way that cannot be bought away with more hardware. That is what scrypt and argon2id do. The cost parameters are not decoration; they are the whole defence, and they have to be retuned upward as hardware gets faster.
GPU, single card, offline guessing against a leaked dump
algorithm cost setting guesses/sec one 8-char password
--------------- ----------------- -------------- ---------------------
SHA-256 plain 10^11 seconds
MD5 plain 10^11 seconds
bcrypt cost 12 10^3 ~ 30 years
scrypt N=2^15, r=8, p=1 10^2 ~ 300 years
argon2id m=64 MiB, t=3 10^1 ~ 3000 yearsRough orders of magnitude for offline guessing on a leaked dump, single modern GPU. Treat the numbers as shape, not gospel: the exact rates move every year, the gaps between rows do not.Multi-factor authentication means proving two things of different kinds: something you know, something you have, or something you are. A password plus a security question is one factor asked twice. What matters in practice is a narrower question than which factors you have: can an attacker who is talking to you right now relay your second factor to the real site before it expires? Codes can be relayed. Keys cannot. The practical distinction is not strength in the abstract, it is whether there is a short-lived secret the attacker can pass along.
Once you are logged in, the server needs to remember that. It can store an opaque random token and look it up on every request, or it can hand you a signed blob of claims and check the signature instead of a database. The second is a JWT, and it is popular for a real reason: any server in a fleet can verify it without talking to a shared store. The price is stated less often. A JWT is valid until it expires, because the only thing the server can do is check a signature, and a signature does not know that you pressed log out. Revoking early means keeping a denylist, which is the state you were trying to avoid. The tradeoff in one table. A JWT is not a better session token; it is a session token that bought statelessness with revocability. Remember me is not a convenience checkbox, it is an expiry decision made on the user behalf. A long-lived token that survives closing the browser is a credential sitting on a device you do not control, and it has to be treated like one: bound to a device, revocable from an account page, and invalidated when the password changes. The honest version of the feature keeps the session long and asks for the password again before anything destructive. The dishonest version keeps a permanent token that nothing but a password reset can kill, and then nobody remembers it exists until a laptop is sold. OAuth answers a question that has nothing to do with who you are: how do I let one service act on another service on my behalf, without giving it my password? You send the user to the provider, the provider asks them to approve a specific set of permissions, and it returns a code that only the requesting app can exchange for a token. The token carries a scope and an expiry. What OAuth deliberately does not define is how to prove identity, which is why OpenID Connect exists as a thin identity layer on top. The consequence is worth remembering: a service that logs you in with a raw OAuth token and nothing else is making an authentication decision out of an authorization mechanism.
Practice
A database of password hashes leaks. Each stored value is scrypt(password, salt) with parameters that take about 100 ms to compute once. Which statement is true?
Hints
- The attacker already has the stored values. A salt is stored right next to them, so it cannot be a secret.
- What makes a password hash expensive to attack is not secrecy but the deliberate cost of computing one guess.
Match each mechanism to what it actually gives you.
Hints
- For each token format ask one question: after it is handed out, can the server still take it back before it expires?
- For each second factor ask a different question: is there a short-lived value the attacker could relay to the real site within its lifetime?
Put the OAuth authorization code flow in order.
- 1the provider returns an access token carrying the approved scope and an expiry
- 2the app exchanges the code, presenting its client secret, and the code is single-use
- 3the provider authenticates the user and shows what is being requested
- 4the app calls the API with that token, and the user password was never involved
- 5the user approves, and the provider returns a short-lived authorization code
- 6the app sends the user to the provider with a client_id and a requested scope
Hints
- Nothing can be issued before the service has decided who is asking and whether the user agreed.
- The client secret is used once, at the moment the app trades the short-lived code for a token, and the token comes last.
Questions about this lesson
Is it free?
Yes. The first level of every subject is free and needs no account. Deeper levels and the senior grades are paid — that is what keeps the project running.
What age is this for?
It is written for curious teenagers from about 12 and for adults starting from zero. Nothing assumes prior programming experience; lessons about networking and physics need no mathematics beyond school level.
Do I need to know programming already?
No. The logic, physics and networking tracks start from nothing. The languages track is where you actually write code, and it also starts from the beginning.
Do I need to install anything?
No. Everything runs in the browser: theory, practice and the interactive simulations. There is nothing to download and no environment to configure.
How long does one subject take?
A lesson takes 10 to 15 minutes. A junior grade is roughly 12 to 20 lessons, so expect a few weeks of steady practice rather than one evening.
Do I have to follow the order?
Within a grade, levels open one after another, because each builds on the previous one. Between subjects you are free: start with logic, physics or networking.