100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Node.js & Express Backend
25 minintermediate

bcrypt, Argon2 and Password Policies

bcrypt, Argon2 and Password Policies

Passwords must never be stored as plain text or reversible encryption. Instead, they are passed through a password hashing function — a deliberately slow, one-way function designed to make brute-force attacks computationally expensive. The two most widely used algorithms in Node.js are bcrypt and Argon2. Understanding their differences, configuring their cost parameters correctly, and enforcing a sensible password policy are foundational security responsibilities for every backend developer.

Analogy🏏Cricket
Think of it like cricket: A team's dressing room has a combination lock. The groundskeeper doesn't keep a notebook of every player's combination — he stores an expensive-to-compute fingerprint of each combination (the hash). To enter, you provide your combination; the system computes the fingerprint and checks it against the stored one. Even if the notebook is stolen, computing the original combination from a fingerprint takes centuries on modern hardware. Rohit Sharma's combination is safe because the fingerprint is deliberately hard to reverse.

bcrypt: The Industry Workhorse

bcrypt was designed in 1999 specifically for password hashing. It incorporates a salt (random bytes mixed into the input) to prevent rainbow table attacks, and a cost factor (work factor) that controls how many iterations of the hashing algorithm are performed. Doubling the cost factor doubles the computation time for both legitimate logins and attackers. The recommended cost factor in 2024 is 12–14, targeting approximately 250–500 ms per hash on a modern server.

bash
npm install bcrypt
javascript
const bcrypt = require('bcrypt');

const SALT_ROUNDS = 12; // adjust so hashing takes ~250-300ms on your hardware

// Hashing a password at registration
async function hashPassword(plaintext) {
  return bcrypt.hash(plaintext, SALT_ROUNDS);
  // bcrypt.hash automatically generates a salt and embeds it in the output
  // Output format: $2b$12$<22-char-salt><31-char-hash>
}

// Verifying at login
async function verifyPassword(plaintext, storedHash) {
  return bcrypt.compare(plaintext, storedHash);
  // Returns true/false; timing-safe comparison built in
}

// Usage
const hash = await hashPassword('Superb@tt1ng!');
console.log(hash); // $2b$12$...

const valid = await verifyPassword('Superb@tt1ng!', hash);
console.log(valid); // true
Analogy🏏Cricket
Think of it like cricket: Scoring in Test cricket is deliberately slow and methodical — that's the point. bcrypt is the Test match of hashing: it takes time on purpose. A fast T20 hash (like MD5) can be brute-forced at billions of attempts per second. bcrypt's cost factor makes each attempt take a quarter of a second, cutting an attacker's throughput from 1 billion to 4 per second. MS Dhoni's patience made him the best finisher; bcrypt's patience makes it the best protector.

Argon2: The Modern Champion

Argon2 won the 2015 Password Hashing Competition and is the current state-of-the-art recommendation. It offers three variants: Argon2i (side-channel resistant), Argon2d (GPU-resistant), and Argon2id (hybrid, recommended). Argon2 allows tuning three independent parameters: time cost (iterations), memory cost (RAM in KiB), and parallelism (threads). Memory-hardness is the key advantage over bcrypt — it forces attackers to use large amounts of RAM per guess, making GPU-based cracking far less effective.

bash
npm install argon2
javascript
const argon2 = require('argon2');

// Hash with Argon2id (recommended variant)
async function hashPasswordArgon2(plaintext) {
  return argon2.hash(plaintext, {
    type:        argon2.argon2id,
    memoryCost:  65536,  // 64 MiB per hash
    timeCost:    3,      // 3 iterations
    parallelism: 4       // 4 threads
  });
}

// Verify
async function verifyPasswordArgon2(plaintext, storedHash) {
  return argon2.verify(storedHash, plaintext);
}

// Rehash detection (if you upgrade parameters later)
async function loginWithRehash(plaintext, storedHash, userId) {
  const valid = await argon2.verify(storedHash, plaintext);
  if (!valid) throw new Error('Invalid credentials');

  if (argon2.needsRehash(storedHash)) {
    const newHash = await hashPasswordArgon2(plaintext);
    await User.updateOne({ _id: userId }, { passwordHash: newHash });
  }
  return true;
}
Analogy🏏Cricket
Think of it like cricket: Argon2 is like a Test match played at altitude in Johannesburg — the conditions themselves are hostile to the opposition. bcrypt makes things slow (time-hard); Argon2 makes things slow AND expensive to run on specialist hardware (memory-hard). An attacker with a GPU farm can run millions of bcrypt guesses in parallel; Argon2's 64 MiB memory cost means even a high-end GPU can only run a handful of guesses simultaneously. Jasprit Bumrah's reverse swing in conditions of high memory-hardness.
Lesson 20 of 36
0% complete