Ayush Agrawal
Ayush Agrawal

Reputation: 23

Bcrypt compare returns false randomly for correct passwords

I am using bcrypt (v2.0.1) in a MERN project (Node v8.10.0) to store user passwords in MongoDB using Mongoose. The hash function:

SellerSchema.pre('save', function (next) {
    var user = this;
    bcrypt.hash(user.password, 10, function (err, hash) {
      if (err) {
        return next(err);
      }
      user.password = hash;
      next();
    });
});

The authenticate part:

SellerSchema.statics.authenticate = function (email, password, callback) {
    Seller.findOne({ email: email })
      .exec(function (error, user) {
        if (error) return callback(error);
        else if (!user) {
          var err = new Error('User not found.');
          err.status = 401;
          return callback(err);
        }
        bcrypt.compare(password, user.password).then(function (result){
          if (result == true) {
            return callback(null, user);
          } else {
            return callback();
          }
        });
      });
}; 

The login route:

router.post('/login', function(req, res, next) {
    if (req.body.email && req.body.password){ 
Seller.authenticate(req.body.email,req.body.password,function(error,user) {
    if (error || !user) {
        console.log("this "+error);
    var err = new Error('Wrong email or password.');  // logged everytime the compare result was false 
    err.status = 401;
    return next(err);
    }  else {
    res.json(user);
    }
});
} else {
var err = new Error('Email and password are required.');
err.status = 401;
return next(err);
}
});

When signing up new users, the hash is stored fine & logging in using the plain-text does passes the compare() for few times, but returns false after that.

If I signup a new user and login, it works again for sometime and then starts returning false. For example: I am still able to login a user registered hours ago (10-15 compares) but not able to login a user created minutes ago (after 1-2 compares)

Using Node : 8.10.0 , OS: Ubuntu 18.04

Upvotes: 1

Views: 713

Answers (1)

Farhan Tahir
Farhan Tahir

Reputation: 2134

your pre('save') middleware is updating password every time you save object.To stop this use isModified function of mongoose like below:

SellerSchema.pre('save', function(next) {
  if (this.isModified('password')) { // check if password is modified then has it
    var user = this;
    bcrypt.hash(user.password, 10, function(err, hash) {
      if (err) {
        return next(err);
      }
      user.password = hash;
      next();
    });
  } else {
    next();
  }
});

Upvotes: 3

Related Questions