Node.js Password Hashing
Websites must never store passwords as plain text. A data leak would expose every account at once. Hashing turns each password into a scrambled code that nobody can reverse. This lesson shows how to hash passwords with the bcrypt library.
The Problem with Plain Text
Imagine a hotel that writes every guest's room key code on a public board. Anyone who reads the board enters every room. A database with plain passwords behaves like that board.
Plain storage Hashed storage +---------+-------------+ +---------+--------------------------+ | user | password | | user | password_hash | +---------+-------------+ +---------+--------------------------+ | asha | mypass123 | | asha | $2b$10$k8Zq...Xe1Lm | +---------+-------------+ +---------+--------------------------+ Leak = everyone exposed Leak = codes stay useless
Hashing and Encryption Differ
- Encryption locks data, and a key unlocks it.
- Hashing works in one direction only. No key exists to reverse it.
A login system never needs the original password. It only needs to compare a new hash with the stored hash.
Why Plain SHA-256 Falls Short
Fast hash functions help attackers. A modern computer tests billions of guesses every second. Password hashing needs a slow function with a built-in random value called a salt.
What a Salt Does
A salt is a random string added to the password before hashing. Two users with the same password receive different hashes. Attackers cannot use prepared tables of common password hashes.
"mypass123" + salt A --> hash 1 "mypass123" + salt B --> hash 2 (different result)
Install bcrypt
npm install bcryptHash a Password
const bcrypt = require("bcrypt");
async function createHash(password) {
const rounds = 10;
return await bcrypt.hash(password, rounds);
}
createHash("mypass123").then(console.log);
// $2b$10$k8Zq...Xe1LmThe number 10 is the cost factor. Each extra point doubles the work. A value between 10 and 12 suits most apps.
Read the Hash
$2b$10$k8ZqExampleSaltValueHereXe1LmHashedPasswordPart | | |_________________|_____________________________ | | salt (22 chars) hash | cost factor algorithm version
The result stores the salt inside itself. You save one text value in the database.
Check a Password
async function verifyPassword(typed, savedHash) {
const match = await bcrypt.compare(typed, savedHash);
return match; // true or false
}The compare function reads the salt from the saved hash, hashes the typed password, and checks the result.
Sign-Up and Login in Express
const users = []; // replace with a database
app.post("/signup", async (req, res) => {
const { email, password } = req.body;
if (!password || password.length < 8) {
return res.status(400).send("Use at least 8 characters.");
}
const passwordHash = await bcrypt.hash(password, 10);
users.push({ email, passwordHash });
res.status(201).send("Account created.");
});
app.post("/login", async (req, res) => {
const { email, password } = req.body;
const user = users.find((u) => u.email === email);
const ok = user && (await bcrypt.compare(password, user.passwordHash));
if (!ok) {
return res.status(401).send("Wrong email or password.");
}
res.send("Welcome back!");
});
SIGN-UP: password --> bcrypt.hash --> save hash
LOGIN: typed password --> bcrypt.compare --> saved hash
|
true --> allow false --> deny
Good Habits
- Show one message for wrong email and wrong password. Separate messages reveal which emails exist.
- Require a minimum length of eight characters or more.
- Use only the async functions in servers. The sync versions block the event loop.
- Never print passwords in logs.
- Add rate limits to login routes to slow guessing attacks.
- Serve the site over HTTPS so passwords travel safely.
Other Options
Argon2 and scrypt are strong alternatives. Node.js includes scrypt in the crypto module. Bcrypt remains a trusted, simple choice for beginners.
Practice Tasks
- Hash the same password twice and compare the two results.
- Write a function that returns true for the correct password and false for a wrong one.
- Change the cost factor from 8 to 12 and measure the time difference.
