Bcrypt illustration

This is an older note on using bcrypt in Node.js.

The main thing I was trying to understand at the time was not really how hashing works in theory, but how to structure it cleanly in an asynchronous code path when creating or validating users.

Why Bcrypt

If you need to store user passwords, the important part is that you do not store them in plain text.

bcrypt is useful because it handles:

  • salting
  • hashing
  • password comparison

At the time, what tripped me up was not the hashing itself. It was how to make the async flow work cleanly with the rest of the application code.

Basic Flow

The basic bcrypt flow looks like this:

var bcrypt = require('bcrypt');

bcrypt.genSalt(10, function(err, salt) {
    bcrypt.hash('B4c0/\\/', salt, function(err, hash) {
        // Store hash in your password DB
    });
});

That part is straightforward.

The thing I was trying to solve was how to return something usable from that async chain so the rest of the server code could continue in a predictable way.

The Approach I Used

At the time, I used Q promises to wrap the async bcrypt work and return a promise from the database layer.

npm install q

The core idea was:

  • create a deferred object
  • do the bcrypt work
  • save the user once the password is hashed
  • resolve or reject the promise

Creating a User

exports.createUser = function(obj) {
    var defer = Q.defer();

    Bcrypt.genSalt(Salt_Factor, function(err, salt) {
        if (err) {
            return console.error(err);
        }

        Bcrypt.hash(obj.password, salt, function(err, hash) {
            if (err) {
                return console.error(err);
            }

            obj.password = hash;

            var user = new User(obj);
            user.save(function(err, user) {
                if (err) {
                    defer.reject(err);
                } else {
                    defer.resolve(user);
                }
            });
        });
    });

    return defer.promise;
};

What mattered to me here was returning defer.promise from the outer function so the caller could keep using .then(...).

Checking a User’s Password

The login side is similar, except instead of generating a salt and hash again, you compare the incoming password against the stored hash.

exports.findUser = function(obj) {
    var defer = Q.defer();

    User.find({ username: obj.username }).then(function(user, err) {
        if (err) {
            console.log('unable to find user', err);
        } else {
            Bcrypt.compare(obj.password, user[0].password, function(err, result) {
                if (err) {
                    defer.reject(err);
                } else {
                    defer.resolve(result);
                }
            });
        }
    });

    return defer.promise;
};

Why This Helped

The main lesson for me was that async security code is not hard because of bcrypt itself. It gets awkward when you need to fit it into the rest of your application flow cleanly.

Returning a promise from the outer function made the calling code much easier to reason about.

Example Request Handler

app.post('/createUser', function(req, res, next) {
    db.createUser(req.body).then(function(user, err) {
        if (err) {
            res.status(406);
        } else {
            res.status(200);
        }
    });
});

This is obviously older Node.js style now, but the core idea still holds: hash before storage, compare on login, and make the async flow easy to work with.