bcrypt

Welcome to a lesson on how to implement strong password security using the bcrypt library. By now, you understand how critical it is to store passwords properly. You know about hashing, salting, and why it’s a terrible idea to write your own hashing algorithms. In this tutorial, you’ll learn how to use bcrypt in a Node.js environment to salt and hash passwords, as well as compare them against user input for authentication.

You will learn how to:

Why bcrypt?

Although you grasp the concepts of salting and hashing, it’s never advisable to roll your own cryptographic functions. Think of a home cook trying to invent a new pasta noodle from scratch—fun, but risky for restaurant-grade reliability. Similarly, writing your own hashing algorithm is error-prone and dangerous for production security.

bcrypt (pronounced “bee-kript”) is a battle-tested algorithm for hashing passwords, automatically handling salt generation and including features to slow down brute-force attacks by adjusting the “work factor.”

In Node.js, we’ll typically use the bcryptjs package, which implements bcrypt in pure JavaScript.

Installing bcrypt

Let’s get started by installing bcryptjs:

npm install bcryptjs

Once installed, import it in your code:

const bcrypt = require('bcryptjs');

This sets us up to generate salted and hashed passwords, as well as compare them during login. Think of bcrypt as your personal guard who does the heavy lifting of password transformations.

Salting and Hashing a Password

To create a salted and hashed password from a plain text input, you can use:

const saltedAndHashedPassword = bcrypt.hashSync(plainTextPassword);

This single method does all the magic:

You can optionally pass a second argument to hashSync to specify the cost factor (e.g., 12 for extra security). A higher cost factor means the hashing takes more time, slowing down potential brute-force attempts.

Example usage in code:

const bcrypt = require('bcryptjs');

const plainTextPassword = "catsanddogs";
const saltedAndHashedPassword = bcrypt.hashSync(plainTextPassword, 10);

console.log("Plain:", plainTextPassword);
console.log("Salted+Hashed:", saltedAndHashedPassword);

This saltedAndHashedPassword is what you store in your database. Like we said before, never store the plain text password; store the salted+hashed string.

Comparing a Salted+Hashed Password with User Input

Next comes authentication. When a user logs in, they provide their plain-text password. You retrieve the stored salted+hashed password from the database, then let bcrypt compare them:

const isMatch = bcrypt.compareSync(plainTextPassword, saltedAndHashedPassword);
if (isMatch) {
  // The user typed the correct password
} else {
  // Invalid password
}

Under the hood, compareSync repeats the hashing process with the stored salt and checks if the resulting hash matches what’s in your database. If they match, you’ve validated the user’s credentials.

Step by Step Example / Follow-Along Exercise

Let’s outline a quick scenario to see how these pieces fit together. Imagine you have an Express route for user registration and one for login.

// registration route
app.post("/register", async (req, res) => {
  const { email, password } = req.body;

  // 1) create salted+hashed version
  const hashedPassword = bcrypt.hashSync(password, 10);

  // 2) save user in database
  await User.create({
    email,
    hashedPassword,  // store only the hashed version
  });

  res.json({ message: "User registered!" });
});

// login route
app.post("/login", async (req, res) => {
  const { email, password } = req.body;

  // 1) find user by email
  const user = await User.findOne({ where: { email } });
  if (!user) {
    return res.status(401).json({ message: "Invalid email or password" });
  }

  // 2) compare passwords
  const isMatch = bcrypt.compareSync(password, user.hashedPassword);
  if (!isMatch) {
    return res.status(401).json({ message: "Invalid email or password" });
  }

  // 3) if match, user is authenticated
  res.json({ message: "Logged in successfully!" });
});

In this simplified code:

That’s essentially all it takes to implement a secure password scheme with bcrypt.

Why This Matters (Real-World Examples)

Applications from social media giants to tiny hobby sites all rely on bcrypt or similar algorithms (like Argon2 or PBKDF2) for password storage. Historically, sites that skipped this step faced severe breaches. For instance, if you follow data breach news, you’ll see many catastrophic headlines about companies storing plaintext passwords or using outdated hashing methods. With bcrypt, you take advantage of a trusted cryptographic library that stands up well against brute-force and rainbow-table attacks.

Also, consider compliance requirements for handling user data. Whether it’s GDPR, HIPAA, or PCI-DSS, secure password storage is often part of the checklist. bcrypt helps ensure you meet those requirements.

Additional Topics to Explore

What You’ve Learned

You’ve seen how bcrypt fits right into your existing knowledge of salting and hashing:

Putting this all together, you now have a complete, best-practice approach for storing and verifying user passwords in Node. This is a major milestone in building secure applications—congratulations!