Password hashing is one of the most common tasks in a web application. Hashing generally maps data of any size to a fixed-length string by using a secure algorithm. It's a one-way function that makes it suitable for authentication.

In an earlier article, I wrote how to encrypt and decrypt strings, numbers, buffers, streams, etc. by using the Node.js built-in crypto module. Today, you'll learn how to use another Node.js open-source library called bcrypt to hash passwords.

The bcrypt library makes it real fun to hash and compare passwords in a Node.js application.

Installation

To use the bcrypt library in a Node.js application, run the following command in your terminal to install it via NPM:

$ npm install bcrypt --save

Now, you can include it in your application:

const bcrypt = require('bcrypt');

Hashing a password

Bcrypt provides both asynchronous and synchronous password hashing methods. The asynchronous mode is recommended because hashing is a CPU intensive task, and the synchronous approach will block the event loop and prevent your application from handling any other incoming requests or events. The asynchronous version uses a thread pool that does not block the main event loop.

Asynchronous Hashing

The bcrypt.hash() function takes in the plain password and a salt as input, and returns a hashed string. Let us write a simple function:

const hashPassword = async (password, saltRounds = 10) => {
    try {
        // Generate a salt
        const salt = await bcrypt.genSalt(saltRounds);

        // Hash password
        return await bcrypt.hash(password, salt);
    } catch (error) {
        console.log(error);
    }

    // Return null if error
    return null;
};

As you can see above, we first generated a salt with bcrypt.genSalt() and then invoke the bcrypt.hash() method to create a hashed string.

The first step is optional. You can directly pass the number of salt rounds to the bcrypt.hash() method to achieve the same end-result:

const hash = await bcrypt.hash(password, saltRounds);

Now, whenever required, just call the above method to hash a password and store it in a database:

(async () => {
    const hash = await hashPassword('123456');
    // $2b$10$5ysgXZUJi7MkJWhEhFcZTObGe18G1G.0rnXkewEtXq6ebVx1qpjYW

    // TODO: store hash in a database
})();

Bcrypt also supports traditional callbacks and JavaScript promises. I prefer to use async-await syntax because it is clean and easier to understand.

Synchronous Hashing

If you prefer to use the synchronous approach instead, just use the following code:

// Generate Salt
const salt = bcrypt.genSaltSync(10);

// Hash Password
const hash = bcrypt.hashSync('123456', salt);

console.log(hash);
// $2b$10$Wdj1lOudt3JXEc6TBI2C6.Wafuv33FRdv9jRd9qtVdPYWmKmbtiTm

You can also auto-generate the salt and hash the password in the same function call:

const hash = bcrypt.hashSync('123456', 10);

Salt Rounds

The saltRounds parameter is critical when you hash a password with Bcrypt. It defines the number of rounds the library should go through to give you a secure hash. Bcrypt also uses this value to go through 2^rounds iterations of processing.

The higher the salt rounds, the more time it will take to generate a secure hash. On a typical 2GHz core you can roughly expect:

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

Comparing passwords

Now if you want to compare the password entered by the user with the previously stored hashed password, just use the bcrypt.compare() method. Let us write a function that verifies if the password entered by the user is valid or not:

const comparePassword = async (password, hash) => {
    try {
        // Compare password
        return await bcrypt.compare(password, hash);
    } catch (error) {
        console.log(error);
    }

    // Return false if error
    return false;
};

The following example demonstrates how you can call the above method to validate a password entered by the user:

(async () => {
    // Hash fetched from DB
    const hash = `$2b$10$5ysgXZUJi7MkJWhEhFcZTObGe18G1G.0rnXkewEtXq6ebVx1qpjYW`;

    // Check if password is correct
    const isValidPass = await comparePassword('123456', hash);

    // Print validation status
    console.log(`Password is ${!isValidPass ? 'not' : ''} valid!`);
    // => Password is valid!
})();

Bcrypt also provides compareSync() method to perform the comparison synchronously:

const isValidPass = bcrypt.compareSync(password, hash);

Conclusion

That's all about hashing passwords using Bcrypt in a Node.js application. You've just learned how to properly hash and verify passwords with Node.js and Bcrypt.

Take a look at Bcrypt docs to learn more about all the available options and API methods.

✌️ Like this article? Follow me on Twitter and LinkedIn. You can also Subscribe to RSS Feed.

Last Updated: