Photo Credit: dzarro72

Tutorial: Easy authentication for Sails.js apps

Matthew Nuzum —  — 14 Comments

Recently I built a demo application using Sails 10.x (currently in beta) and needed to add authentication support to it. One of the challenges with this is that the documentation for the beta Sails is not complete yet, and much has changed. The documentation is still great, so I definitely recommend making it your first stop.

While browsing through NPM modules I found sails-generate-auth which looked like an excellent solution for authentication. Yes, it works, but unfortunately the documentation is not written very well. The Github page makes it look like all you need is a configuration file and you’re set. In reality, there is a bit more work to do. Here are the steps I took.

First, I’ll point out that this is not the only way to add Passport authentication to your app. By the way, I’m a firm believer in using Passport or other community supported authentication frameworks rather than rolling your own. There have been numerous cases of large sites with big development teams getting hacked and having their user database stolen. I say this merely to point out that authentication is more difficult than it looks. Using a tool that allows you to get the benefits of other developers with different types of experience collaborating together should help you.

I’m going to assume you’ve already started a Sails.js app and you have some routes configured and working. Now you need to install the module:

npm install sails-generate-auth --save

Now you need to look at the file config/locales/en.json. In mine, I merely have an object with one line, "Welcome": "Welcome". This file will be in the way and you need to move it. Make a note of the line, then delete the file.

Once you do that, we can generate our authentication with this command:

sails generate auth

If you mixed up the order of those last two steps you’ll get an error: “Something else already exists at config/locales/en.json“. Once you fix that and re-run generate auth you’ll get an error “Something else already exists at api/services/protocols” which is a folder created by the generate auth command. Simply delete that folder and then run generate auth. You probably want to edit config/locales/en.json and add the Welcome line back in.

At this point you now should have an AuthController, a Passport model, a passport.js config file as well as a few other files that you won’t need to edit in order to get started.

You’ll need to create a User model that contains the information you need for your user profile. Here’s an example of the file I created:

module.exports = {

 schema: true, 

 attributes: {
 username : { type: 'string', unique: true },
 email : { type: 'email', unique: true },
 passports : { collection: 'Passport', via: 'user' }
 }
};

Next we need to configure the login strategy. Two common examples are local and Twitter login. Before you can use these you have to install the module. Therefore you may need to install passport-local or passport-twitter. In this case, I’ll use Twitter.

npm install passport-twitter --save

Now you need to configure your authentication protocol. If you view config/passport.js you’ll see a bunch of example configurations. Comment out or remove all but the one you want. In this case you’ll end up with a file that looks like this:

module.exports.passport = {
  twitter: {
    name: 'Twitter',
    protocol: 'oauth',
    strategy: require('passport-twitter').Strategy,
    options: {
      consumerKey: 'your-consumer-key',
      consumerSecret: 'your-consumer-secret'
    }
  }
}

You’ll need to visit the Twitter developer center to register your application. After you create your application make sure you click the settings tab and then check the box at the bottom of the form to enable the credentials to be used to sign in to Twitter. Grab the API key and secret and drop them into the config.

We’re almost done!

Edit config/bootstrap.js and before the cb() call near the end of the file, add this line:

sails.services.passport.loadStrategies();

Then edit config/policies.js change ‘*’: true, to

'*': [ 'passport' ],

Now edit config/routes.js and set these routes up as the first routes:


  'get /login': 'AuthController.login',
  'get /logout': 'AuthController.logout',
  'get /register': 'AuthController.register',

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

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

Now, for the /login page I simply created a view that looks like this: (note I’m using Handlebars)


      {{#each providers}}
        <a href="/auth/{{slug}}">{{name}}</a>
      {{/each}}

This will give you a list of all your authentication strategies. In my case, I’m only using Twitter, so it will give me a link to login with Twitter. You’ll see some help and example code in AuthController.js.

At this point, you should have a working authentication strategy and you’ll be able to customize this to meet your needs.

However, there is one thing you’re definitely going to want to customize quickly: Sessions. By default, Sails.js uses in memory session storage, which is fine for local testing. However, every time you edit a file your Sails.js server will restart, either automatically or manually. When this happens, the in-memory session store gets cleared out. That means you’ll have to log in every time you edit a file!

It’s not a huge deal for something like Twitter, but you’ll quickly tire of it. The two built in session storage options are Redis and Mongo. You can configure them in config/session.js.

If you find a way to use the local db that Sails.js uses as a session store, please let me know. I don’t think it’s hard, there just needs to be an adapter created and then a patch submitted to the Sails.js developers.

If it helped, please share!Tweet about this on TwitterShare on FacebookShare on LinkedInShare on Google+

Matthew Nuzum

Posts Twitter Facebook

Web guy, big thinker, loves to talk and write. Front end web, mobile and UX developer for John Deere ISG. My projects: @dsmwebgeeks @tekrs @squaretap ✝
  • vishal

    Hi Mathew

    First of all thank you for this wonderful post as there is really very less available regarding this module

    Whatever you have elaborated in the blog is clear though i am facing problems in registering and logging in

    After creating the project as per your description i can see a collection named passport in my mongo db (Through command line) but i am not able to understand the action defined on signup and login

    As per my understanding Here auth is for the contoller, local in the local strategy and register is the register action defined in AuthController.

    after clicking on register i redirect to http://localhost:1337/auth/local/register

    and a error of page forbidden is displayed.
    Can you please help me know what i am doing wrong

    Thanks in advance

    • I had the same problem and for me it was the missing

      input(type=”hidden”, name=”_csrf”, value=”#{_csrf}”)

      in both, the register and login form. Now it works like a charm!

  • David Adler

    When trying to sign in with google I get the following error

    Error: invalid_request

    Missing required parameter: scope

    Why is that?

    • John Fedoruk

      in config/passport.js:

      google: {
      name: ‘Google’,
      protocol: ‘oauth2’,
      strategy: require(‘passport-google-oauth’).OAuth2Strategy,
      options: {
      clientID: ”,
      clientSecret: ”,
      scope : [‘profile’,’email’]
      }
      }

      You’ll also want to add the following in services/passport.js (around line 90):

      // If the profile object contains a displayName instead of a username, add it to the user.
      else if (profile.hasOwnProperty(‘displayName’)) {
      user.username = profile.displayName;
      }

  • tom_m

    For anyone else having issues with an error about the passport middleware not being in use, I found this tutorial (http://blog.thesparktree.com/post/77311774912/creating-a-sails-application-using-passport) discussed an extra step I didn’t see here in adding the middleware. Look at #4 there. Basically the middleware needs to be added to express (which Sails.js uses) under a config/express.js file. Pretty simple.

    • Richard Powell

      Thank you so much for this. For anyone else, the error I was getting was happening when registering. Specifically:

      Error: passport.initialize() middleware not in use

  • weijie gao

    greate post! really helped with setting up passport!

  • Adam

    Great walkthrough, thanks.

    Which file does the user model go in?

  • Sean

    Thanks Matthew, I was having trouble getting the session authentication working with my front end and Sails. This did it for me. Many thanks and smiling happy Llamas headed your way!

  • cadianshock

    I just get “Error: HTTP Basic authentication strategy requires a verify function at new BasicStrategy (/Users/me/Sites/demo/node_modules/sails-auth/node_modules/passport-http/lib/passport-http/strategies/basic.js:46:22)”

    Its like its trying to use HTTP even though my passport.js only contains the local config.

    • cadianshock

      I got it working! I somehow how was using sails-auth and sails-generate-auth, the former was error-ing and removing it fixed the issue.

      • newz2000

        Glad it’s working and also excited to hear that this tutorial still has some use.

      • John Negoita

        Hi Jake, thank you for saving me a couple of hours of searching 🙂

        and Mathew, thank you for the tut, it is very useful

  • slenkar

    How do I list the providers with ejs instead of handlebars?