How to hash passwords using Bcrypt in Node.js

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.

You might also like...

Digital Ocean

The simplest cloud platform for developers & teams. Start with a $200 free credit.

Buy me a coffee ☕

If you enjoy reading my articles and want to help me out paying bills, please consider buying me a coffee ($5) or two ($10). I will be highly grateful to you ✌️

Enter the number of coffees below:

✨ Learn to build modern web applications using JavaScript and Spring Boot

I started this blog as a place to share everything I have learned in the last decade. I write about modern JavaScript, Node.js, Spring Boot, core Java, RESTful APIs, and all things web development.

The newsletter is sent every week and includes early access to clear, concise, and easy-to-follow tutorials, and other stuff I think you'd enjoy! No spam ever, unsubscribe at any time.