Show Buttons
Share On Facebook
Share On Twitter
Share On Google Plus
Share On Linkdin
Share On Reddit
Share On Stumbleupon
Contact us
Hide Buttons

Setup passportjs for local authentication and authorization using expressjs

Signup and login are the most com­monly found use cases in web appli­ca­tions. In this post, I will doc­u­ment how you can use Pass­portjs to setup authen­ti­ca­tion and autho­riza­tion for your appli­ca­tions locally. Pass­portjs also lets you man­age OAUTH based authen­ti­ca­tion and we will see more exam­ples of using Pass­port with OAUTH in the future posts.


Pack­ages

npm install --save passport passport-local passport-github connect-flash

For the pur­pose of this demo, I will also be using a library called ‘async’ that makes it easy and clear to process mul­ti­ple asyn­chro­nous functions.

npm install --save async

Pass­port Setup

Next, we will cre­ate a file where we con­fig­ure pass­port to per­form the authen­ti­ca­tion. In our case, I will be cre­at­ing a config/passport.js file.

Lets setup the skele­ton of this file

config/passport.js

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

// Create a list of users just for demo.
// In reality, you will probably query a database
// to fetch this user
var users = {
  [email protected]': {
    id: 'userOne',
    password: 'one',
    email: [email protected]'
  },
  [email protected]': {
    id: 'userTwo',
    password: 'two',
    email: [email protected]'
  }
};

function createAccount (payload, callback) {
    // Call API to create account
    users[newUser.email] = newUser;
    callback(null, newUser);
}

// Invokes callback with an error if email already exists, null otherwise
function findExistingEmail (email, callback) {
    // Call API to check if the email already exists
    if(users[email]) {
      callback({err: 'Email Already Exists'});
    } else {
      callback(null, null);
    }
}

module.exports = function (passport) {
    // All our authentication code for signup and signin will go here
}

Con­tin­u­ing with our module.exports, we will now define the func­tions that han­dle the ses­sion data once a user has suc­cess­fully authenticated.

config/passport.js

module.exports = function (passport) {

  passport.serializeUser(function(user, done) {
    // This is what passport will save in the session/cookie
    done(null, user.email); 
  });

  passport.deserializeUser(function(email, done) {
    // Use the email saved in the session earlier
    // to fetch the actual user
    var user = users[email];
    done(null, user);
  });

}


SignIn

Lets add our first cru­cial func­tion where we will per­form the actual task of login.

config/passport.js

module.exports = function (passport) {

    // ...

    // We name our strategy 'local-login'.
    // You can use any name you wish
    // This is the name you will refer to later in a route
    // that handles the login on client request
    passport.use('local-login', new LocalStrategy({
        usernameField : 'email',
        passwordField : 'password',
        passReqToCallback : true
    },
    function(req, email, password, done) {
      if(users[email] && users[email].password === password) {
        return done(null, users[email]);
      } else {
        done(null, false, req.flash('message', 'Invalid email or password'));
      }
    }));

}

As you can tell in the code above, I expect the login form to have two fields with the names — ‘email’ and ‘pass­word’ respec­tively. Also, by set­ting the pass­Re­q­To­Call­back to true, I can access any other fields on the request object if need be.


SignUp

Now, lets write some code that han­dles signup. For our case, I will use async to chain the func­tion. We will first check if the email already exists. If not, asynch will pro­ceed with invok­ing the func­tion that cre­ates an account.

config/passport.js

passport.use('local-signup',
  new LocalStrategy({
    usernameField : 'email',
      passwordField : 'password',
      passReqToCallback : true // Pass back the entire request to the callback
    }, function (req, email, password, done) {

      process.nextTick(function() {

        async.auto({
          doesEmailAlreadyExist: function (cb, results) {
            findExistingEmail(email, cb);
          },
          newAccount: ['doesEmailAlreadyExist',
            function (cb, results) {

              var newUser = {
                email: email,
                password: password
              };
              createAccount(newUser, cb);
            }
          ]
        }, function (err, results) {
          if (err) {
            done(null, false, req.flash('signupMessage', err.message));
          } else {
            done(null, results.newAccount);
          }
        });

      });
  })
);

With that out of the way, lets setup our app.js and make it pass­port aware.


Setup app.js

Add the fol­low­ing lines of code just below your first set of vari­able declarations.

app.js

// --- Authentication ---
var passport = require('passport'),
  flash = require('connect-flash');

require('./config/passport')(passport);

app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
// --------

Since we are using a ses­sion, pass­port requires express.session to be ini­tial­ized before it can be used. In our code, the express ses­sion was already ini­tial­ized a few lines ago such as

app.js

app.use(session({
  secret: config.session.SESSION_SECRET, // This can be any string
  saveUninitialized: true,
  resave: true
}));

We will also include the pass­port ref­er­ence in our set­tings object that is passed down to all the routes

app.js

var settings = {
    config: config,
    passport: passport
};


Route han­dlers

Now that we have every­thing in place, lets cre­ate sim­ple route han­dlers for the login and signup actions.

In our routes folder, I will cre­ate a file called auth.js that will han­dle all the login actions. In the future, we will add route han­dlers for OAUTH based login strate­gies in the same file.

routes/auth.js

module.exports = function(app, settings){
  var url = require('url'),
    express = require('express'),
    router = express.Router(),
    passport = settings.passport;

  router.post('/local-login', passport.authenticate('local-login', {
    successRedirect : '/home.html',
    failureRedirect : '/login.html',
    failureFlash : true
  }));

  router.post('/local-signup', passport.authenticate('local-signup', {
    successRedirect : '/home.html',
    failureRedirect : '/signup.html',
    failureFlash : true
  }));

  app.use('/auth',router);
};

If you look at the code above, in my router, I han­dle the local-signup and local-signin actions tand spec­ify the han­dler func­tion to be pass­port authen­ti­cate. The first argu­ment for authen­ti­cate must match the name of the strat­egy that we used in our pass­port con­fig­u­ra­tion file we cre­ated ear­lier. Note that I named every­thing the same for con­sis­tency and ease of maintenance.

Also, we add this newly added route han­dler file to our routes/index.js

routes/index.js

// Divide all of your modules in different files and
// require them here
module.exports = function(app, settings){
    require('./main')(app, settings);
    require('./auth')(app, settings);
    require('./home')(app, settings);
};

And thats pretty much it. Now you can cre­ate a login and signup form that sub­mits to the above url’s and you’re all set to use pass­port as a way to login and reg­is­ter for your application.

The full source code for this demo can be found in the passport-local-login branch of the node-starter-kit repository.


Ryan Sukale

Ryan is a UX engineer living in San Francisco, California.