I like tomatoes

Implement Passport.js authentication with Sails.js ~0.10

Due to the number of outdated examples about this subject that I've seen on the web, I might save your day by writing an updated, working one, by myself.

Step 1: dependencies

Add these dependencies to the yourproject/package.json file:

  "dependencies": {
    "bcrypt": "~0.8.0",
    "passport": "~0.2.1",
    "passport-local": "~1.0.0",

Open the terminal, go to your project folder and run:

[sudo] npm install

Step 2: create user model

To create a user model run the following command:

sails generate api user

This will automatically create a model and a controller. You can find the model at yourproject/api/models/User.js. Let's make that file look like this:

var bcrypt = require('bcrypt');

module.exports = {
    attributes: {
        email: {
            type: 'email',
            required: true,
            unique: true
        password: {
            type: 'string',
            minLength: 6,
            required: true
        toJSON: function() {
            var obj = this.toObject();
            delete obj.password;
            return obj;
    beforeCreate: function(user, cb) {
        bcrypt.genSalt(10, function(err, salt) {
            bcrypt.hash(user.password, salt, function(err, hash) {
                if (err) {
                } else {
                    user.password = hash;

Step 3: create AuthController

Run this command from your terminal:
sails generate controller auth

Then go to yourproject/api/controllers/AuthController.js and alter it in this way:

var passport = require('passport');

module.exports = {

    _config: {
        actions: false,
        shortcuts: false,
        rest: false

    login: function(req, res) {

        passport.authenticate('local', function(err, user, info) {
            if ((err) || (!user)) {
                return res.send({
                    message: info.message,
                    user: user
            req.logIn(user, function(err) {
                if (err) res.send(err);
                return res.send({
                    message: info.message,
                    user: user

        })(req, res);

    logout: function(req, res) {

Step 4: create login and signup views

Create this file yourproject/views/signup.ejs:

<form method="POST" action="/user">
  <input type="email" name="email">
  <input type="password" name="password">
  <input type="submit" value="submit">

And then this yourproject/views/login.ejs:

  <form method="POST" action="/login">
  <input type="email" name="email">
  <input type="password" name="password">
  <input type="submit" value="submit">

These forms look the same, besides the action.

Step 5: configuring the routes

Let's set up our routes in yourproject/config/routes.js like this:

module.exports.routes = {
  '/': {
    view: 'homepage'

  'get /login': {
       view: 'login'

  'post /login': 'AuthController.login',

  '/logout': 'AuthController.logout',

  'get /signup': {
    view: 'signup'

If you notice we are leveraging HTTP verbs, we have two login actions but different routes.

Step 6: configuring Express Middleware

Since we are using Passport we have to customize our middleware in yourproject/config/http.js:

module.exports.http = {
   middleware: {

    passportInit    : require('passport').initialize(),
    passportSession : require('passport').session(),

     order: [

Into the order array we added passportInit and passportSession after the session element. The name of this array is quite self-explanatory, the elements must be ordered this way.

Step 7: define Passport local strategy for authentication

Into yourproject/config/ folder let's create a new file called passport.js:

var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy,
bcrypt = require('bcrypt');

passport.serializeUser(function(user, done) {
    done(null, user.id);

passport.deserializeUser(function(id, done) {
    User.findOne({ id: id } , function (err, user) {
        done(err, user);

passport.use(new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password'
  function(email, password, done) {

    User.findOne({ email: email }, function (err, user) {
      if (err) { return done(err); }
      if (!user) {
        return done(null, false, { message: 'Incorrect email.' });

      bcrypt.compare(password, user.password, function (err, res) {
          if (!res)
            return done(null, false, {
              message: 'Invalid Password'
          var returnUser = {
            email: user.email,
            createdAt: user.createdAt,
            id: user.id
          return done(null, returnUser, {
            message: 'Logged In Successfully'

Step 8: add a new policy

Let's create a new policy isAuthenticated.js into the yourproject/api/policies/ folder:

module.exports = function(req, res, next) {
   if (req.isAuthenticated()) {
        return next();
        return res.redirect('/login');

Briefly, we are telling Sails what to do if a user is not authenticated, then we can bind this policy to any of the controllers in the app.

Step 9: bind the policy to a controller

Let's create a controller and a model just for testing what we have done. I am going to call this api post.

sails generate api post

Then let's bind the policy to the PostController by updating yourproject/config/policies.js:

module.exports.policies = {

   '*': true,

  'PostController': {
    '*': 'isAuthenticated'


Now the 'GET /post' route (and all the other routes automatically generated for this controller ) is available only to authenticated users.

Step 10: run a test

Lift your application
sails lift
And then go and play with these routes:

  1. http://localhost:1337/post - the very first time it should redirect you to the login page

  2. go to http://localhost:1337/signup for signing up

  3. go to http://localhost:1337/login for logging in

  4. now you should be able to access this page http://localhost:1337/post, even though it's going to show you just an empty array (there aren't any posts yet)

  5. go to http://localhost:1337/logout for logging out

→ Get the repository on Github

I would very much appreciate your comments, especially if you find an error or you need a further explanation.