pfried pfried - 11 months ago 81
Node.js Question

Mongoose password hashing

I am looking for a good way to save an Account to MongoDB using mongoose.

My problem is: The password is hashed asynchronously. A setter wont work here because it only works synchronous.

I thought about 2 ways:

  • Create an instance of the model and save it in the callback of the
    hash function.

  • Creating a pre hook on 'save'

Is there any good solution on this problem?

Answer Source

The mongodb blog has an excellent post detailing how to implement user authentication.

The following is copied directly from the link above:

User Model

var mongoose = require('mongoose'),
    Schema = mongoose.Schema,
    bcrypt = require('bcrypt'),

var UserSchema = new Schema({
    username: { type: String, required: true, index: { unique: true } },
    password: { type: String, required: true }

UserSchema.pre('save', function(next) {
    var user = this;

    // only hash the password if it has been modified (or is new)
    if (!user.isModified('password')) return next();

    // generate a salt
    bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
        if (err) return next(err);

        // hash the password using our new salt
        bcrypt.hash(user.password, salt, function(err, hash) {
            if (err) return next(err);

            // override the cleartext password with the hashed one
            user.password = hash;

UserSchema.methods.comparePassword = function(candidatePassword, cb) {, this.password, function(err, isMatch) {
        if (err) return cb(err);
        cb(null, isMatch);

module.exports = mongoose.model('User', UserSchema);


var mongoose = require(mongoose),
    User = require('./user-model');

var connStr = 'mongodb://localhost:27017/mongoose-bcrypt-test';
mongoose.connect(connStr, function(err) {
    if (err) throw err;
    console.log('Successfully connected to MongoDB');

// create a user a new user
var testUser = new User({
    username: 'jmar777',
    password: 'Password123';

// save user to database {
    if (err) throw err;

// fetch user and test password verification
User.findOne({ username: 'jmar777' }, function(err, user) {
    if (err) throw err;

    // test a matching password
    user.comparePassword('Password123', function(err, isMatch) {
        if (err) throw err;
        console.log('Password123:', isMatch); // -> Password123: true

    // test a failing password
    user.comparePassword('123Password', function(err, isMatch) {
        if (err) throw err;
        console.log('123Password:', isMatch); // -> 123Password: false