Jope
Jope

Reputation: 146

Express, passport: can't set headers after they are sent

I'm still a noob to node and webdev, but trying hard!
I get this error : can't set headers after they are sent

with the following while using passport.js and bcryptjs compare method for password validation on a mean stack

routes/login.js

var express = require('express')
var router = express.Router()
var mongoose = require('mongoose')
var User = mongoose.model('User')
var passport = require('passport')

router.post('/', function (req, res, next){

    passport.authenticate('local', function(err, user, info){
        if(err){ return next(err); }

        if(user){  
              return res.json({token: user.generateJWT()});    
        } else {     
              return res.status(401).send(info)   
        }

    })(req, res, next);
});

module.exports = router

authenticate/local.js

var passport = require('passport')
var LocalStrategy = require('passport-local').Strategy
var mongoose = require('mongoose')
var User = mongoose.model('User')
var bcrypt = require('bcryptjs')

passport.use(new LocalStrategy(function(username, password, done) {
  User.findOne({
    username: username
  }, function(err, user) {
    if (err) {
      return done(err)
    }
    if (!user) {
      return done(null, false, {
        message: {
          username: 'Incorrect     username.'
        }
      })
    }

    bcrypt.compare(password, user.password, function(err, isMatch) {
      if (err) {
        return done(err)
      }
      if (!isMatch) {
        return done(null, false, {
          message: {
            password: 'Incorrect password'
          }
        })
      }
    });

    return done(null, user);
  });

}));

This validates correctly for a valid username and password, and logs in.

For an invalid username, it correctly rejects the login attempt.

But for an invalid password, it logs in and then crashes the app with the Can't set headers error.

However if i change the bcrypt.compare to bcrypt.compareSync, then all validations are correct.

if (!bcrypt.compareSync(password, user.password)) {
  return done(null, false, {
    message: {
      password: 'Incorrect password'
    }
  });
}

I would rather not depend on the sync methods, so help me please understand where I am going wrong!

Upvotes: 1

Views: 683

Answers (1)

mscdex
mscdex

Reputation: 106696

bcrypt.compare() is async but you're calling done(null, user) immediately. Move it inside the callback and it should be fine:

bcrypt.compare(password, user.password, function(err, isMatch) {
  if (err) { return done(err) }
  if (!isMatch) {
    return done(null, false, { message: { password: 'Incorrect password' } })
  }
  done(null, user)
})

Upvotes: 3

Related Questions