So I've been trying to write an authentication system on my VueJs app with PassportJs
. I wrote a function to initialize the basics of PassportJs
that looks like this:
module.exports = {
passport: function () {
authenticateUser = async (email, password, done) => {
User.findOne({ email: email }, async (err, user) => {
if (user == null) return done(null, false, { msg: 'No user registered with this email' })
try {
if (await bcrypt.compare(password, user.password)) {
return done(null, user)
} else {
return done(null, false, { msg: "Password incorrect" })
}
} catch (e) {
return done(e)
}
})
}
passport.use(new LocalStrategy({ usernameField: 'email', }, authenticateUser));
passport.serializeUser((user, done) => {
console.log('passport serializeUser')
done(null, user.id)
})
passport.deserializeUser((id, done) => {
console.log('passport deserializeUser')
User.findById(id, (err, user) => {
done(err, user)
})
})
},
};
Now, literally the only thing that I need is to display the proper error messages on the front end.
This code works for displaying the error messages, but does NOT work for actually logging in the users:
router.post('/login', function (req, res, next) {
passport.authenticate('local', function (err, user, info) {
if (err) { return next(err); }
if (!user) {
console.log('mand?????: ', info)
res.status(401).json({ msg: info.msg });
return;
}
})(req, res, next);
});
I can see that this code gets run (await bcrypt.compare(password, user.password))
but it does not serialize the user. The request just keep 'pending' but does not finish.
This code works for actually logging in the user, but does NOT work for displaying the error messages:
router.post('/login', passport.authenticate('local'))
Where am I going wrong? How can I login the user succesfully, but also display the proper error messages as declared int he done()
function from passportjs?
Take a look at passport
documentation for the authenticate()
method.
When using a custom callback, it becomes the application's responsibility to establish a session (by calling
req.login()
) and send a response.
So in your first scenario, you need to explictly establish a session - passport will not do it automatically for you.
Regarding your second scenario where no custom callback is used:
By default, if authentication fails, Passport will respond with a 401 Unauthorized status, and any additional route handlers will not be invoked.
As far as I understand, with this setup, flash messages set up as part of the Strategy
verify callback are not being used - unless redirect
options are specified, which you do not want here.
So you probably should go with the first scenario in order to be able to customize error responses with the Strategy
verify callback flash messages. Just make sure you establish the session when login is successful.
http://www.passportjs.org/docs/authenticate/
Edit: I've just ran through a quick test, and it seems that alternatively you should be able to get away with just having the Strategy
verify callback return errors with the error.message
property set to whatever error message you want to send as a response - without the need for the custom callback and flash messages at all. Note though that in this case passport actually sets the response body to the error message as text.
So for instance instead of:
done(null, false, { msg: 'No user registered with this email' })
You would do:
done(new Error('No user registered with this email')