Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Express Passport (node.js) error handling

I've looked at how error handling should work in node via this question Error handling principles for Node.js + Express.js applications?, but I'm not sure what passport's doing when it fails authentication. I have the following LocalStrategy:

passport.use(new LocalStrategy({ usernameField: 'email', passwordField: 'password' },
  function(email, password, next) {
 
    User.find({email: UemOrUnm}, function(err, user){
      if (err) { console.log('Error > some err'); return next(err); }
      if (!user) { console.log('Error > no user'); return next('Incorrect login or password'); } 

      if (password != user.password) {
        return next(Incorrect login or password);
      }
      return next(null, user);
    });
  }
));

After I see 'Error > some err' console printout, nothing else happens. I would think it should continue on the the next path with an error parameter, but it doesn't seem to do that. What's going on?

like image 477
Omid Ahourai Avatar asked Mar 29 '13 20:03

Omid Ahourai


People also ask

How does Passport js handle authorization?

Authorization is performed by calling passport. authorize() . If authorization is granted, the result provided by the strategy's verify callback will be assigned to req.account . The existing login session and req.

What does passport authenticate () do?

In this route, passport. authenticate() is middleware which will authenticate the request. By default, when authentication succeeds, the req. user property is set to the authenticated user, a login session is established, and the next function in the stack is called.

What is Passportjs?

Passport is authentication middleware for Node.js. Extremely flexible and modular, Passport can be unobtrusively dropped in to any Express-based web application. A comprehensive set of strategies support authentication using a username and password, Facebook, Twitter, and more.


3 Answers

The strategy-implementation works in conjunction with passport.authenticate to both authenticate a request, and handle success/failure.

Say you're using this route (which is passed an e-mail address and a password):

app.post('/login', passport.authenticate('local', {
  successRedirect: '/loggedin',
  failureRedirect: '/login', // see text
  failureFlash: true // optional, see text as well
});

This will call the code in the strategy, where one of three conditions can happen:

  1. An internal error occurred trying to fetch the users' information (say the database connection is gone); this error would be passed on: next(err); this will be handled by Express and generate an HTTP 500 response;
  2. The provided credentials are invalid (there is no user with the supplied e-mail address, or the password is a mismatch); in that case, you don't generate an error, but you pass a false as the user object: next(null, false); this will trigger the failureRedirect (if you don't define one, a HTTP 401 Unauthorized response will be generated);
  3. Everything checks out, you have a valid user object, so you pass it along: next(null, user); this will trigger the successRedirect;

In case of an invalid authentication (but not an internal error), you can pass an extra message along with the callback:

next(null, false, { message : 'invalid e-mail address or password' });

If you have used failureFlash and installed the connect-flash middleware, the supplied message is stored in the session and can be accessed easily to, for example, be used in a template.

EDIT: it's also possible to completely handle the result of the authentication process yourself (instead of Passport sending a redirect or 401):

app.post('/login', function(req, res, next) {
  passport.authenticate('local', function(err, user, info) {
    if (err) {
      return next(err); // will generate a 500 error
    }
    // Generate a JSON response reflecting authentication status
    if (! user) {
      return res.send({ success : false, message : 'authentication failed' });
    }
    // ***********************************************************************
    // "Note that when using a custom callback, it becomes the application's
    // responsibility to establish a session (by calling req.login()) and send
    // a response."
    // Source: http://passportjs.org/docs
    // ***********************************************************************
    req.login(user, loginErr => {
      if (loginErr) {
        return next(loginErr);
      }
      return res.send({ success : true, message : 'authentication succeeded' });
    });      
  })(req, res, next);
});
like image 148
robertklep Avatar answered Oct 21 '22 22:10

robertklep


What Christian was saying was you need to add the function

req.login(user, function(err){
  if(err){
    return next(err);
  }
  return res.send({success:true});
});

So the whole route would be:

app.post('/login', function(req, res, next) {
  passport.authenticate('local', function(err, user, info) {
    if (err) {
      return next(err); // will generate a 500 error
    }
    // Generate a JSON response reflecting authentication status
    if (! user) {
      return res.send(401,{ success : false, message : 'authentication failed' });
    }
    req.login(user, function(err){
      if(err){
        return next(err);
      }
      return res.send({ success : true, message : 'authentication succeeded' });        
    });
  })(req, res, next);
});

source: http://passportjs.org/guide/login/

like image 24
cpoole Avatar answered Oct 21 '22 23:10

cpoole


You need to add req.logIn(function (err) { }); and do the success redirect inside the callback function

like image 3
Christian Nagorka Avatar answered Oct 21 '22 23:10

Christian Nagorka