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 theerror
message and thehash
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 😉