21

in the passport [configure authentication] documentation, it has a rather scary-looking function that uses the mysterious function "done.'

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: 'Incorrect username.' });
      }
      if (!user.validPassword(password)) {
        return done(null, false, { message: 'Incorrect password.' });
      }
      return done(null, user);
    });
   }
));

Now, in the express documentation there are quite a few methods that pass something called next.

app.use(function(err, req, res, next){
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

Is this the difference between the two frameworks, express and passport? Or are they doing two separate things?

laggingreflex
  • 32,948
  • 35
  • 141
  • 196
Tara Roys
  • 1,756
  • 2
  • 17
  • 31
  • In general, the naming of a parameter does not make any difference to its functionality – Bergi Oct 02 '14 at 16:11
  • So they do the same thing, it's just documented in two different ways for these two different frameworks? – Tara Roys Oct 02 '14 at 16:13
  • I'd guess they both are typical node callbacks with the `err` parameter conventions, so nothing "scary" or "odd". Whether passport does different things with the values that you pass in than express (or whether it just passes them through) I cannot tell, but the docs of the library should do. – Bergi Oct 02 '14 at 16:17
  • The passport callback is described in (slightly) more detail here under the [verify callback section](http://passportjs.org/guide/configure/) – dc5 Oct 02 '14 at 16:28
  • What is the purpose of the `return` statements? Is it just to avoid `else if` ? Does `done` return anything useful? – agentofuser Mar 14 '18 at 15:44

4 Answers4

20

Is this the difference between the two frameworks, express and passport?

No they are different in the purpose for which they are used for. Express is used as a application framework on node.js where as passport just handles the authentication part of a web application.

about next()

next() is part of connect which inturn is an express dependency. The purpose of calling next() is to trigger the next middle ware in express stack.

To understand the next() concept in an easier way, you could look at a sample app built on express here.

as you can see in the line pointed the application uses a route level middleware to check whether the user is logged in or not.

app.get('/account', ensureAuthenticated, function(req, res){

Here ensureAuthenticated is the middleware which is defined at bottom like

function ensureAuthenticated(req, res, next) {
  if (req.isAuthenticated()) { return next(); }
  res.redirect('/login')
}

as you can see if the user is authenticated the function invokes next() and passes control to the next layer in route handler written above, else it redirects to another route even without invoking the next()

about done()

done() on the other hand is used to trigger the return url handlers that we write for passport authentication. To understand more on how done works you could look at the code samples at passport here and check the section titled Custom Callback

app.get('/login', function(req, res, next) {
  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);
});

Here the second parameter to passport.authenticate is the definition of done() that you are going to call from the passport strategy.

note

Here going through the sample codes in the two links I provided above have helped alot in understanding its behavior than the docs. I would suggest you to do the same.

Community
  • 1
  • 1
Mithun Satheesh
  • 27,240
  • 14
  • 77
  • 101
  • OP doesn't ask about the difference between the frameworks (which is obvious), but about the way they use the `next`/`done` async callbacks – Bergi Oct 02 '14 at 16:19
  • @Bergi: sorry i was adding more detail into it. I have updated the answer. – Mithun Satheesh Oct 02 '14 at 16:39
  • Thanks, looks better :-) Though I'm not sure why `req, res, next` are both used in that `done` callback *and* passed into the result of the `authenticate` function? – Bergi Oct 02 '14 at 16:46
  • in this particular example they are invoking the authenticate function manually rather than as a middleware on the route, I think thats the reason for the extra function call with `req, res, next` – Mithun Satheesh Oct 02 '14 at 17:02
  • I just wondered, when would passport call `next` directly, instead of calling the `done` callback? – Bergi Oct 02 '14 at 17:07
  • 1
    @Bergi: req, res are not avalable in the passport strategy definition. Only thing we could access is the done function inside which we could use these variables and implement the logics like redirection. – Mithun Satheesh Oct 02 '14 at 17:18
6

passport's done() wants you to pass in an error (or null) for the first param and a user object as the 2nd param.

express's next() wants an error in the first param or to be called with no parameter at all if there wasn't an error. you could also pass the name of a route to redirect control to in the first parameter but this isn't very common

Robert Levy
  • 28,747
  • 6
  • 62
  • 94
6

Let's back up because I think you may have some confusion.

Express is a web application framework. It's responsible for directing users to resources, in a very broad sense.

Passport is a authentication framework. It's responsible for making sure that users are allowed to access said resources.

In both frameworks there is a idea of middleware. Middleware is basically generalized control flow. For example, in some Express framework you could say:

  1. Make sure parameter x is valid when requesting route /user/:x

    • if valid, then next() --> which means go to next middleware function()
  2. Make sure the user has a session, etc

  3. And when all middleware has been executed, then we execute the application

For example,

router.get('/', function(req, res) { // when the '/' route is requested
    res.render('index', { title: 'Express' }); // send index.html
});

In Passport, they also use the idea of middleware, however, instead of next(), they use done() and it's a little more complex. See this page for more info
http://toon.io/understanding-passportjs-authentication-flow/

Andrew Lohr
  • 5,380
  • 1
  • 26
  • 38
Jason
  • 126
  • 4
0

next() will get the control flow to the next middleware, if there is.

In Passport.js, Calling done() will make the flow jump back into passport.authenticate(). It's passed the error, user and additional info object (if defined).

In other cases, done() will take the control flow to the next function after the function it was used in.