Script Valley
Node.js: The Complete Runtime
Authentication and SecurityLesson 5.3

Password hashing and secure login in Node.js

bcrypt vs scrypt, bcrypt salt rounds, password storage, login flow, timing-safe comparison, brute force protection, rate limiting

Never Store Plaintext Passwords

Use bcrypt for password hashing. It is battle-tested, includes a salt automatically, and has an adjustable cost factor.

npm install bcrypt
const bcrypt = require('bcrypt');
const SALT_ROUNDS = 12;

async function hashPassword(plaintext) {
  return bcrypt.hash(plaintext, SALT_ROUNDS);
}

async function verifyPassword(plaintext, storedHash) {
  return bcrypt.compare(plaintext, storedHash);
}

Secure Login Endpoint

app.post('/api/login', async (req, res) => {
  const { email, password } = req.body;
  const user = await User.findByEmail(email);

  const dummyHash = '$2b$12$notavalidhashbutstillruns';
  const hash = user ? user.passwordHash : dummyHash;
  const valid = await bcrypt.compare(password, hash);

  if (!user || !valid) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }

  const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { expiresIn: '15m' });
  res.json({ token });
});

Up next

Securing Express APIs: helmet, rate limiting, and CORS

Sign in to track progress

Password hashing and secure login in Node.js โ€” Authentication and Security โ€” Node.js: The Complete Runtime โ€” Script Valley โ€” Script Valley