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 about how to encrypt and decrypt strings, numbers, buffers, streams, etc. by using the Node.js built-in crypto module. Today, you'll learn to use another Node.js open-source library called bcrypt for hashing passwords.

The bcrypt library makes it 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.

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 stop the main event loop.

Asynchronous Hashing

The bcrypt.hash() function takes the plain password and 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 later invoked 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 processing iterations.

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 the 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 the 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 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.