Password hashing is essential for security in any Node.js app. Let’s go step by step and cover why, how, and best practices using bcrypt.
1️⃣ Why Hash Passwords?
-
Never store plain-text passwords — if your DB is breached, users’ credentials are exposed.
-
Hashing converts the password into a fixed-length, irreversible string.
-
Salting adds randomness, making hash attacks much harder.
2️⃣ Install bcrypt
npm install bcryptjs
-
bcryptjs
→ pure JS implementation (works everywhere) -
Alternatively,
bcrypt
→ faster native bindings
3️⃣ Hashing a Password
const bcrypt = require("bcryptjs");
const hashPassword = async (plainPassword) => {
const salt = await bcrypt.genSalt(10); // generate salt (complexity = 10)
const hashedPassword = await bcrypt.hash(plainPassword, salt);
return hashedPassword;
};
// Example usage
(async () => {
const password = "superSecret123";
const hashed = await hashPassword(password);
console.log(hashed); // $2a$10$...
})();
4️⃣ Verifying Passwords
When a user logs in, compare the plain password with the hashed password in DB:
const comparePassword = async (plainPassword, hashedPassword) => {
const isMatch = await bcrypt.compare(plainPassword, hashedPassword);
return isMatch;
};
// Example
const isValid = await comparePassword("superSecret123", hashedFromDB);
console.log(isValid); // true or false
5️⃣ Integrating with User Registration/Login
Registration (hash password before saving)
const register = async (req, res) => {
try {
const { name, email, password } = req.body;
const hashedPassword = await bcrypt.hash(password, 10);
const user = await User.create({ name, email, password: hashedPassword });
res.status(201).json({ message: "User created", userId: user._id });
} catch (err) {
res.status(400).json({ error: err.message });
}
};
Login (verify password)
const login = async (req, res) => {
try {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user) return res.status(400).json({ error: "Invalid credentials" });
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) return res.status(400).json({ error: "Invalid credentials" });
res.json({ message: "Login successful" });
} catch (err) {
res.status(500).json({ error: err.message });
}
};
6️⃣ Best Practices
-
Never store plain-text passwords
-
Use a strong salt →
bcrypt.genSalt(10)
is standard -
Do not log hashed passwords
-
Use async functions → avoid blocking the event loop
-
Set strong password policies → min length, complexity
✅ Summary
-
bcrypt
= secure hashing for passwords -
Hash passwords before saving, compare during login
-
Protects user data even if DB is compromised
-
Works well with JWT, OAuth, or any authentication system
Next, we can go through refresh tokens + token rotation to handle long-lived sessions securely alongside JWT and bcrypt authentication.
Do you want to go there next?