Hashing passwords in NodeJS with bcrypt library tutorial

The bcrypt npm package is a JavaScript implementation of the bcrypt password hashing function that allows you to easily create a hash out of a password string. Unlike encryption which you can decode to get back the original password, hashing is a one-way function that can’t be reversed once done.

When the user submits a password, the password will be hashed and your JavaScript application needs to store the hash in the database. Later when the user wants to authenticate his or her account, you need to compare the password input with the hash stored in your database to see if it matches.

The bcrypt library makes the process easy by providing you with methods to hash and compare passwords.

To start using the library, you need to install it with your package manager:

npm install bcrypt
# or
yarn add bcrypt

Then include the module to your JavaScript code with require:

const bcrypt = require("bcrypt");

Creating a password hash with bcrypt

To generate a password using the bycrypt module, you need to call on the hash() method which accepts the following three parameters:

  • The password string that you wish to hash
  • The number of rounds to secure the hash. The number commonly ranges from 5 to 15
  • The callback function to execute when the hash process is finished, passing along the error message and the hash result

Here’s an example of bcrypt.hash() processing the password string "generic":

const bcrypt = require("bcrypt");

bcrypt.hash("generic", 5, function (err, hash) {
  console.log(hash);
  // TODO: Store the hash in your password DB
});

Or you can use the synchronous method equivalent called hashSync():

const bcrypt = require("bcrypt");

const myPlaintextPassword = "generic";
const hash = bcrypt.hashSync(myPlaintextPassword, 5);
console.log(hash);

Generating salt for the hash

A hashing function requires you to add salt into the process. A salt is simply a random data that’s used as an additional input to the hashing function to safeguard your password. The random string from the salt makes the hash unpredictable.

In the code examples above, the salt is auto-generated by bcrypt module, but you can actually generate the salt first before hashing the password.

To generate a salt, you can use the genSalt() method from the module:

const bcrypt = require("bcrypt");

bcrypt.genSalt(10, function (err, salt) {
  console.log(salt); // the random salt string
});

Once you have the salt, you can pass it to the hash() method as follows:

const bcrypt = require("bcrypt");

bcrypt.genSalt(10, function (err, salt) {
  bcrypt.hash("generic", salt, function (err, hash) {
    console.log(hash);
    // Store hash in your password DB.
  });
});

There’s also a synchronous equivalent for the method called genSaltSync():

const salt = bcrypt.genSaltSync(10);
const hash = bcrypt.hashSync("generic", salt);

Note that there’s no differences on the resulting hash whether you generate a salt separately or automatically, but the CPU usage may be lowered when you separate the salt generation and the hash process. You should test if your NodeJS server can handle auto-generating the salt and hash first before separating them.

A note on the salt round number

The salt generation for your hash function can range from a few seconds to many days, depending on how many rounds you passed. The bcrypt module will go through 2^rounds to generate the salt to give you a secure hash.

According to the documentation, here’s the amount of time to process the salt generation on a 2GHz core computer:

rounds=8 : ~40 hashes/sec
rounds=9 : ~20 hashes/sec
rounds=10: ~10 hashes/sec
rounds=11: ~5  hashes/sec
rounds=12: 2-3 hashes/sec
rounds=13: ~1 sec/hash
rounds=14: ~1.5 sec/hash
rounds=15: ~3 sec/hash
rounds=25: ~1 hour/hash
rounds=31: 2-3 days/hash

The number is just an estimation, so you may want to test the highest rounds with the fastest generation time that your server can support.

Verifying a password with bcrypt

Once you saved the hash to the database, you can compare the user’s plain text input with the stored hash using the compare() method.

The compare() method accepts three parameters:

  • The plain string password for comparison
  • The hash string created earlier
  • And the callback function once the comparison process is finished

The method will pass the error err object and the boolean value result, telling you whether the comparison matches or not.

Here’s an example of the compare() method in action:

const bcrypt = require("bcrypt");

bcrypt.hash("generic", 5, function (err, hash) {
  console.log(hash);
  // The hash returned, continue to compare
  bcrypt.compare("generic", hash, function (err, result) {
    console.log("generic:", result); // generic: true
  });

  bcrypt.compare("falsy", hash, function (err, result) {
    console.log("falsy:", result); // falsy: false
  });
});

The module also provides the synchronous method compareSync for you to use:

const bcrypt = require("bcrypt");

const myPlaintextPassword = "generic";
const hash = bcrypt.hashSync(myPlaintextPassword, 5);
const result = bcrypt.compareSync(myPlaintextPassword, hash);
console.log(result); // true

After the comparison is finished, you need to provide the right authentication code according to the returned result.

Using promise or async/await instead of callback function

Finally, bcrypt module also supports the use of promise and async/await code style, so you can use them instead of callbacks to make your code cleaner.

Here’s an example of using promises in the hash process:

const bcrypt = require("bcrypt");

bcrypt
  .hash("generic", 5)
  .then((hash) => {
    return bcrypt.compare("generic", hash)
    .then((result) => {
      console.log("generic:", result); // generic: true
    });
  })
  .catch((err) => {
    console.log(err);
  });

And another example using the async/await style:

const bcrypt = require("bcrypt");

async function passwordHashTest(password) {
  const hash = await bcrypt.hash(password, 5);

  const result = await bcrypt.compare(password, hash);
  console.log(result); // true
}

passwordHashTest("generic"); // test the async function

And that’s how the bcrypt module in NodeJS works 😉

Take your skills to the next level ⚡️

I'm sending out an occasional email with the latest tutorials on programming, web development, and statistics. Drop your email in the box below and I'll send new stuff straight into your inbox!

No spam. Unsubscribe anytime.