How to handle unauthorized requests with nodejs/passport

Adam K Dean picture Adam K Dean · Oct 7, 2014 · Viewed 17.7k times · Source

As per the documentation, if I was handle authentication requests like so, I would be able to capture successful attempts.

app.post('/login',
  passport.authenticate('local'),
  function(req, res) {
    // If this function gets called, authentication was successful.
    // `req.user` contains the authenticated user.
    res.redirect('/users/' + req.user.username);
  });

But, like the documentation says:

By default, if authentication fails, Passport will respond with a 401 Unauthorized status, and any additional route handlers will not be invoked. If authentication succeeds, the next handler will be invoked and the req.user property will be set to the authenticated user.

How can I handle the unauthorized login attempt?

I know I can handle it with custom middleware but is there a better way?

Answer

Mithun Satheesh picture Mithun Satheesh · Oct 7, 2014

You should have a look at the Custom Callback section in passport docs which explains about how to override the built in behavior of handling an authentication request. You can write a custom callback which will serve as the done function that you are invoking from the Strategy.

app.get('/login', function(req, res, next) {
  /* look at the 2nd parameter to the below call */
  passport.authenticate('local', function(err, user, info) {
    if (err) { return next(err); }
    if (!user) { return res.redirect('/login'); }
    req.logIn(user, function(err) {
      if (err) { return next(err); }
      return res.redirect('/users/' + user.username);
    });
  })(req, res, next);
});

Look at the second parameter to the passport.authenticate call, which will serve as the done function that you invoke from the local strategy.

See the done function invoked in the code below, which is the local strategy that you define for passport. You can call the done function with various available parameters like err, user, info set from the strategy according to the response from API call or db operation. These parameters will be processed by the above function definition in the passport.authenticate call.

passport.use(new LocalStrategy(
  function(username, password, done) {
    /* see done being invoked with different paramters
       according to different situations */
    User.findOne({ username: username }, function (err, user) {
      if (err) { return done(err); }
      if (!user) { return done(null, false); }
      if (!user.verifyPassword(password)) { return done(null, false); }
      return done(null, user);
    });
  }
));