Latest Posts

Integrating passport.js into sails.js v0.10.x

For a recent project I was trying to implement digest authentication in a sails.js app. My requirements were to protect a ‘login’ endpoint, which would provi...

For a recent project I was trying to implement digest authentication in a sails.js app. My requirements were to protect a ‘login’ endpoint, which would provide a JWT token to the requestor.

Passport.js

Passport.js is the de-facto authentication middleware for express.js. This is recommended by sails.js policies documentation, thought those docs feels a little scanty on details.

How To Implement Passport.JS Authentication with Sails.JS is useful as a starter, but it was for sails 0.9.x, which allowed for easy insertion of express custom middleware - this has been deprecated in the 0.10.x releases. Also, doing Basic/Digest Auth is a little different, as there

Sails 0.10.x changes

The main change is that most of the original express.js configuration has been pushed into http.js.

Before we start, some basics of express middleware are detailed in Express.js Middleware Demystified.

One of the changes is that it allows for the ordering of express middleware. This wasn’t readily exposed previously, and the new http.js allows you to insert your own middleware at the appropriate moment.

Do note, the order matters, as each middleware is run from top to bottom, and they are allowed to modify the req and res objects - if a earlier middleware depends on a property inserted by a later middleware…you get the picture.

In config/http.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
module.exports.http = {
  middleware: {
    order: [
      'startRequestTimer',
      'cookieParser',
      'session',
      'initPassport', // passport.js init after session
      'bodyParser',
      'handleBodyParserError',
      'compress',
      'methodOverride',
      'poweredBy',
      '$custom',
      'router',
      'www',
      'favicon',
      '404',
      '500'
    ],

    initPassport: require('passport').initialize()
  }
};

Notice we did not enable session support via require('passport').session(), as we don’t need the server to retain the session state for APIs.

For my use case, which is the provide protected API endpoints, I wanted to enforce Digest Authentication on requestors. Digest Auth is widely supported, and is reasonably safe, as long as one uses HTTPS to secure the connection.

Passport.js allows for this easily with the passport-http’s Digest Auth Strategy.

For this, we will create a new sails service, api/services/Passport.js (I’m assuming there is already a User model existing, with the attributes username and password) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var passport = require('passport'),
  DigestStrategy = require('passport-http').DigestStrategy;

passport.use(new DigestStrategy({
    qop: 'auth'
  },
  function(username, done) {
    User.findOne({username: username})
      .then(function (user) {
        if (!user) return done(null, false);
        return done(null, user, user.password);
    }).catch (function (err) {
      return done(err);
    });
  }
));

So now we’re done with the setup of Digest auth - all that’s left is to invoke it when a controller action is called.

For this, we will create a new policy, api/policies/auth.js:

1
module.exports = require('passport').authenticate('digest', {session: false});

Don’t forget to map the policy in config/policies.js:

1
2
3
module.exports.policies = {
  '*': 'auth'
}

And we’re done!

Digest Auth Success!

Hello world again.

It’s been quite some time since I last decided to maintain a blog, and with the influx of social media, the barrier for getting your thoughts out drops even lower. Even so, in blogs, there is room for long prose, so I will do my best to go beyong 140 characters here. :)