Auth server using Sails.js and Passport.js

I am not fanatic of any language or framework (er, maybe Swift ๐Ÿ˜ž). I think of languages as a tool to solve problems. I was pretty comfortable with my Python / Django stack. Then I was drawn by all the buzz around websockets, and real time apps. So back in 2014, I started tinkering with Node.js. I kind of liked Express. Very minimalistic, yet powerful. Socket.io was amazing. Everything was a wow factor for me.

With few tinkering, I knew I need to learn Node. Next, I wanted to select a framework and master it. Eventhough I liked Express, I had to make myself disciplined, else the codebase would get all nasty. I was looking for something similar to Django where there are few preset convensions that you abide to follow. Then Sails.js caught my eyes. Sails was still in its early stage (0.10.4 I guess). I did a bit of research on sails. There were a few blog posts where authors shared their bitter experience with the framework. But I thought, what the hell, letโ€™s go for it.

Sails has been awesome for prototyping. Few command line statements and you are all set. I started on working on a hobby project and thus learning Sails. At times, I have felt integrating third party libraries to sails is a daunting task. I wanted authentication logic and the obvious solution was to use Passport.js. There were tons of tutorials on how to integrate passport with express, but a very few on how to with sails.

I got it to work somehow. And it was ugly.

Time flew. Now sails is at 0.12.11 and I thought its a good time to refactor my old code. There are several npm modules for authentication like sails-auth. There had been a fallout in sails core team and the maintainer of sails-auth started off with his own version of framework Trails.js. Well, and he stopped maintaining the sails-auth module. Though he occassionaly accepted the pull requests, last publish to npm was over an year ago. And the npm version has lot of bugs. Yup.

I like sails. I wanted a boilerplate authentication server using sails and passport.js, which is extensible. Sails-auth is an excellent module (github version). I only had to glue the bits and pieces together.

First you need to create config/passport.js

module.exports.passport = {
  local: {
    strategy: require('passport-local').Strategy
  },

  basic: {
    strategy: require('passport-http').BasicStrategy,
    protocol: 'basic'
  },

  jwt: {
    algorithm: 'HS256',
    strategy: require('passport-jwt').Strategy,
    options: {
      jwtFromRequest: require('passport-jwt').ExtractJwt.fromAuthHeader(),
      secretOrKey: 'meow',
      issuer: 'thenullpointer.in',
      audience: 'thenullpointer.in',
      passReqToCallback: false,
      expiresIn: 1 * 60 * 60 // seconds
    }
  } 
  /* You can add in more strategies here. */
};

Copy files api/controllers, api/models, api/policies, api/services, config/routes, config/policies and lib folder from https://github.com/mjzac/SailsAuthServer to respective locations in your sails app.

Modify config/bootstrap.js with following content to load various passport strategies.

module.exports.bootstrap = function(cb) {

  // It's very important to trigger this callback method when you are finished
  // with the bootstrap!  (otherwise your server will never lift, since it's waiting on the bootstrap)
  sails.services.passport.loadStrategies();
  cb();
};

You need to install various passport strategies before lifting the server.

npm install passport passport-local passport-jwt passport-http jsonwebtoken bcryptjs base64url

Now you are good to go.

The available urls are:

  'post /register': 'UserController.create',
  'post /logout': 'AuthController.logout',

  'post /auth/local': 'AuthController.callback',
  'post /auth/local/:action': 'AuthController.callback',

  'get /auth/:provider': 'AuthController.provider',
  'get /auth/:provider/callback': 'AuthController.callback',
  'get /auth/:provider/:action': 'AuthController.callback'

register endpoint accepts email and password as parameters.

email = theEmail@provider.com
password = MeowMeowMeow

To test the passport-local strategy, send post request to /auth/local/

identifier = theEmail@provider.com
password = MeowMeowMeow

To test the passport-jwt strategy, send post request to /auth/local/?jwt=1

identifier = theEmail@provider.com
password = MeowMeowMeow

Once you get jwt token, send the request to /user/me with jwt token in authorization header

Authorization: JWT <token>

If evrything is right, you should get the userโ€™s data as response. Oh! and I use Postman to send your requests. :)

Clone the code from Github