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.