Node JSProgramming

Bcrypt: Implementing Encryption With Node.js

How to use Bcrypt.js to secure passwords in Node.js

Getting Started

I’m not going to go over all of the pro’s and con’s of bcrypt or 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:

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 the first, so I switched to the second after debugging. This fixed all of the issues I was having.

Hash and encryption went from 3 seconds, to <100ms. The difference is to do with the way it’s ported from c++ and additionally has no dependencies, so there’s no need to worry about security from sub-dependency updates. For these reasons alone, I’d recommend bcrypt.js (second package) every time.

Installing & Authentication Class

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

$ npm install bcryptjs

Now lets make a simple authentication class that will house our functions for logging in and password checking.

It’s also worth noting that I’m using TypeScript here. You can just remove the any type annotations and use it like regular ES6.

import * as bcrypt from 'bcryptjs';
export default class Auth {
    public static hashPassword(password: string, rounds: number, callback: (error: Error, hash: string) => void) : void {
        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.

The callback receives two parameters. Either an error, or a valid hash. You can perform an if else on this to make sure you always have a valid hash.

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
            }
        });
    }
}

Hashing Passwords

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: (error: string | null, match: boolean | null) => void) {
    bcrypt.compare(password, dbHash, (err: Error, match: boolean) => {
        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’.

Database Login Authentication

public static login(email, password) {
    mysql.connection.query('SELECT * FROM user WHERE email = ?', [email], (error: Error, results: any[]) => {
        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, (error: string | null, match: boolean | null) => {
                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.

In case 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. For this reason, we use callbacks so whilst CPU time is being shared, your web service can still accept incoming requests.

I also have a post on JWT Tokens if you’re looking to expand this into a fully fledged login system.

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

Related Articles

Leave a Reply

Back to top button