How to use bcrypt in nodejs

 

I’m not going to go over all of the pro’s and con’s of encryption, how it works or which one you should use. There are already lots of great cryptographers who write about this stuff and know far more than I do so I’ll leave that side of the tech mumbo-jumbo to those who know what they’re doing. That being said, you can read a few recommended resources here:
1. why you should use bcrypt
2. how cryptography works

So assuming you’ve already decided to use bcrypt, this article will look over a simple implementation of this.

Before we jump into the code, I’d just like to warn you that there are actually two versions of bcrypt available on NPM as of right now.
1. https://www.npmjs.com/package/bcrypt
2. https://www.npmjs.com/package/bcryptjs

I ran into issues with performance and gyp-rebuilds with #1, so I found #2 while debugging and it fixed all my issues. Hash and encryption went from 3 seconds, to 100ms. the difference is to do with the way it’s ported from c++ and #2 has no dependencies, so there’s no need to worry about security from sub-dependency updates as there aren’t any.

So lets start with the basics, getting it up and running. To begin with, lets install the package via NPM


$ npm install bcryptjs

import * as bcrypt from 'bcryptjs';

export default class Auth {

    public static hashPassword(password: string, rounds: number, callback: Function) {
        bcrypt.hash(password, rounds, (error, hash) => {
            callback(error, hash);
        });
    }
}

Inside another class, we can now use this without instantiating the class thanks to the static methods.


import Auth from './../utils/auth';

export default class SomeClass {

    public myFnct() {
        Auth.hashPassword('myPassword', 12, (err, hash) => {
            if(err) {
                // throw and error
            } else {
                // store the new hash in the database etc
            }
        });
    }
}

Next lets work on creating new passwords. Salts are automatically stored in the hash itself, so there’s no need to store the salt as a separate field in the database. Go ahead and create another public static method in our Authentication class


public static compare(password: string, dbHash: string, callback: Function) {
    bcrypt.compare(password, dbHash, (err, match) => {
        if(match) {
            // passwords match
            callback(null, true);
        } else {
            // passwords do not match
            callback('Invalid password match', null);
        }
    });
}

And then we’d call this after retrieving the password from the database. I’ll include some psudo code from mysql for reference, but I’ll go over this in more depth with a series on authentication and user verification. Lets add another method to our example ‘someClass’.


    public static login(email, password) {
        mysql.connection.query('SELECT * FROM user WHERE email = ?', [email], (error, results) => {
            if(error) {
                // there was an error in the mysql
            } else {
                // selects return an array, so access the first in the array
                let user = results[0];
                // now lets compare the passwords
                Auth.compare(password, user.password, (err, match)) => {
                    if(error) {
                        // passwords did not match
                    } else {
                        // passwords match
                    }
                }
            }
        });
    }

Just to go over the block of code above. We have a login method that accepts en email and a password. We select the user’s data from the database from their email. If there isn’t an error, we then take the password the user entered, and the password stored in the database from the mysql lookup, and pass both to the compare method in the Authentication class. The resulting callback tells us if the passwords match.

Incase any of you are wondering why the need for callbacks, bcrypt is very cpu intensive (which is a good thing for protecting against hackers). Because of this, if we choke the event-loop with encryption and decryption, then your requests will queue up. I’ll be covering some great performance tips in another article.

If you have any questions or errors, please feel free to comment and I’ll reply as soon as I can.

Twitter

Error code 89: Invalid or expired token.

Stay Updated