Password hashing

BackendTier 2 · build and shipPhase 3 · Give customers accounts

Storing a scrambled, one-way version of a password instead of the real thing, so even the company never knows it.

A product must check passwords, but storing them as plain text means one database leak hands attackers every account, and people reuse passwords everywhere. Keeping the real password around is the danger. Password hashing exists to store only a one-way scramble of the password, so the system can verify a login without ever holding the secret it could lose.

Storing real passwords would be catastrophic; one breach and every account is exposed. Instead, the server runs the password through a one-way scramble (a hash) and stores only the result. The scramble cannot be reversed.

When you log in, the server scrambles what you typed and compares the two scrambles. Match means correct. This is why support can reset your password but never tell you what it was: nobody, not even the database, holds the original.

A junior PM, stuck

A CX lead asked me why support cannot just email a customer her forgotten password, since surely we have it in our database, and I could not give a straight answer. I said something vague about security and felt like I was guessing. I need to actually understand what the users table holds so I can explain it without hand-waving.

We do not have her password, and the proof is one column in the users table. What we store is a one-way scramble of the password, and one-way means exactly that: there is no way to run it backwards into the original. Here is the real password_hash value from one row, split into its parts, and next to it what the server does at login, so you can see it check a password without ever holding one.

The password_hash column for one users row, and the login-time check
The stored hash, split at its separators
$2b$
12$
R9h/cIPz0gi.URNNX3kh2O
PST9/PgBkqquzi.Ss7KIUgO2t0jWMUW
What the server does when she logs in
input: the password she just typed
run bcrypt(input) using the salt from the stored hash
compare the fresh digest to the stored digest
equal: login ok not equal: reject

Click a step to see the lines it points at.

Telling a customer support can look up her old password. Support can only reset it; the plaintext exists nowhere, so a retrieve-my-password flow cannot be built correctly no matter how the ticket is worded.
Calling hashing the same thing as encryption. Encryption is reversible with a key, on purpose; a password hash is deliberately one-way with no key that turns it back, and conflating them leads to asking engineers for something impossible.
Waving off the salt as a technical detail. Without the per-user salt, identical passwords hash identically and one leaked table cracks in bulk against a precomputed list.
Treating the cost factor as noise. It is the dial between a login that is fast for the user and expensive for an attacker, and quietly lowering it to speed up sign-in weakens every account in the table.

Tell the CX lead: "We can't email her the password because we never store it. The users table holds only a one-way bcrypt hash, so nobody, including us, can read the original. The correct flow is a reset link that lets her set a new one." You read a hash into its algorithm, cost, salt, and digest, and could explain why the original is gone for good. That is the skill.

"We don't store passwords" is the correct, expected answer. If anyone suggests keeping real passwords, that is a red flag.
This is why password reset means setting a new one, never "here is your old password." Understanding that shapes the reset flow you design.

"We can't email them their password, we only store the hash. Send a reset link."

Appears in Phase 3, Give customers accounts.