Be the first user to complete this post

  • 0
Add to List

Setup passportjs for local authentication and authorization using expressjs

Signup and login are the most commonly found use cases in web applications. In this post, I will document how you can use Passportjs to setup authentication and authorization for your applications locally. Passportjs also lets you manage OAUTH based authentication and we will see more examples of using Passport with OAUTH in the future posts.

Packages

npm install --save passport passport-local passport-github connect-flash
For the purpose of this demo, I will also be using a library called 'async' that makes it easy and clear to process multiple asynchronous functions.
npm install --save async

Passport Setup

Next, we will create a file where we configure passport to perform the authentication. In our case, I will be creating a config/passport.js file. Lets setup the skeleton 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
}
Continuing with our module.exports, we will now define the functions that handle the session data once a user has successfully 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 crucial function where we will perform 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 'password' respectively. Also, by setting the passReqToCallback to true, I can access any other fields on the request object if need be.

SignUp

Now, lets write some code that handles signup. For our case, I will use async to chain the function. We will first check if the email already exists. If not, asynch will proceed with invoking the function that creates 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 passport aware.

Setup app.js

Add the following lines of code just below your first set of variable 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 session, passport requires express.session to be initialized before it can be used. In our code, the express session was already initialized 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 passport reference in our settings object that is passed down to all the routes app.js
var settings = {
    config: config,
    passport: passport
};


Route handlers

Now that we have everything in place, lets create simple route handlers for the login and signup actions. In our routes folder, I will create a file called auth.js that will handle all the login actions. In the future, we will add route handlers for OAUTH based login strategies 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 handle the local-signup and local-signin actions tand specify the handler function to be passport authenticate. The first argument for authenticate must match the name of the strategy that we used in our passport configuration file we created earlier. Note that I named everything the same for consistency and ease of maintenance. Also, we add this newly added route handler 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 create a login and signup form that submits to the above url's and you're all set to use passport as a way to login and register 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.



Also Read:

  1. set the default node version using nvm
  2. Organizing your expressjs routes in separate files.
  3. Scaling a basic nodejs application using clusters
  4. How to publish a package on npm
  5. Configuring jshint as a pre-commit hook for your nodejs applications