Passport Authentication for Node.js Applications

In this tutorial, we’ll be implementing authentication via Facebook and GitHub in a Node.js web application. For this we’ll be using Passport, an authentication middleware for Node.js. Passport supports authentication with OpenId/OAuth providers.

Express Web Apps

Before getting started, make sure you have Node.js installed on your machine. You will also require Express, a framework for building web apps that is inspired by Ruby’s Sinatra. In order to install Express, from the terminal type the following command.

npm install -g express

If you get a permission access error then try the same command using sudo. Once Express is installed, we can generate a project skeleton using the following command.

express AuthApp

This creates the following project directory structure.

create : AuthApp
create : AuthApp/package.json
create : AuthApp/app.js
create : AuthApp/public
create : AuthApp/public/images
create : AuthApp/public/stylesheets
create : AuthApp/public/stylesheets/style.css
create : AuthApp/routes
create : AuthApp/routes/index.js
create : AuthApp/routes/user.js
create : AuthApp/views
create : AuthApp/views/layout.jade
create : AuthApp/views/index.jade
create : AuthApp/public/javascripts

Next, install the application’s dependencies using the following commands.

cd AuthApp
npm install

You can now start the server by typing node app.js. To verify that everything is working properly, navigate to http://localhost:3000, where you should be greeted with a welcome message. Please note that the skeleton app we have generated uses a deprecated feature in the file AuthApp/views/layout.jade. If you receive an error message, simply change the first line of this file to read doctype html.

Implementing Facebook Authentication

Before we can implement authentication, we need to install the Passport module using the command shown below.

npm install passport

Once this is done, create a new file, AuthApp/html/auth.html, with the following contents.

<html>
  <head>
    <title>Node.js OAuth</title>
  </head>
  <body>
    <a href="/auth/facebook">Sign in with Facebook</a>
    <br></br>
    <a href="/auth/github">Sign in with Github</a>
  </body>
</html>

We want our default route to serve this HTML page. In app.js there is already a route for /. Modify that route to serve this file as shown in the following code sample. Once this is done, restart the Node server and refresh your browser, and you should see this page.

app.get('/', function(req, res, next) {
  res.sendfile('./html/auth.html');
});

Now, we can implement Facebook authentication. First, we must register a new Facebook app. To do so, visit Facebook, and click on the Create App option of the right hand corner menu. You will be prompted for a display name and several other properties of your new app. Take special note of the App ID and App Secret. Since we’re developing locally, set App Domains as localhost. Our Site URL, which acts as the callback URL is going to be http://localhost:3000/auth/facebook/callback. The following figure shows what our app’s settings look like.

Facebook App Setup

Next, install the passport-facebook module using the command npm install passport-facebook. Once this is done, open app.js and add the following code near the top of the file.

var passport = require('passport');
var FacebookStrategy = require('passport-facebook').Strategy;

var FACEBOOK_APP_ID = 'your app id';
var FACEBOOK_APP_SECRET = 'your app secret';

In app.js we also need to include the Passport middleware. Before the line that reads:

app.use(app.router);

Add these two lines:

app.use(passport.initialize());
app.use(passport.session());

Next, we need to configure the Facebook strategy. The strategy is configured by providing the clientID, clientSecret, and callbackURL as shown below.

passport.use(new FacebookStrategy({
  clientID: FACEBOOK_APP_ID,
  clientSecret: FACEBOOK_APP_SECRET,
  callbackURL: 'http://localhost:3000/auth/facebook/callback'
}, function(accessToken, refreshToken, profile, done) {
  process.nextTick(function() {
    //Assuming user exists
    done(null, profile);
  });
}));

process.nextTick() behaves much like setTimeout(). For more detailed info, take a look here. In the callback, we call done() with the user’s profile if they exist, or false otherwise.

The next step is to set up routes for handling the Facebook authentication:

app.get('/auth/facebook', passport.authenticate('facebook'));

app.get('/auth/facebook/callback', passport.authenticate('facebook', {
  successRedirect: '/success',
  failureRedirect: '/error'
}));

When an authentication succeeds, a session is established and is maintained via a cookie. Passport will need to serialize and deserialize user instances to support sessions. Therefore, serializeUser and deserializeUser callbacks are also required.

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

passport.deserializeUser(function(obj, done) {
  done(null, obj);
});

After all of our changes, this is what app.js looks like:

/**
 * Module dependencies.
 */
var express = require('express');
var routes = require('./routes');
var user = require('./routes/user');
var http = require('http');
var path = require('path');
var passport = require('passport');
var FacebookStrategy = require('passport-facebook').Strategy;

var FACEBOOK_APP_ID = 'your app id'
var FACEBOOK_APP_SECRET = 'your app secret';

var app = express();

// all environments

app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));

// development only
if ('development' == app.get('env')) {
  app.use(express.errorHandler());
}

passport.use(new FacebookStrategy({
  clientID: FACEBOOK_APP_ID,
  clientSecret: FACEBOOK_APP_SECRET,
  callbackURL: 'http://localhost:3000/auth/facebook/callback'
}, function(accessToken, refreshToken, profile, done) {
  process.nextTick(function() {
    done(null, profile);
  });
}));

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

passport.deserializeUser(function(obj, done) {
  done(null, obj);
});

app.get('/auth/facebook', passport.authenticate('facebook'));

app.get('/auth/facebook/callback', passport.authenticate('facebook', {
  successRedirect: '/success',
  failureRedirect: '/error'
}));

app.get('/success', function(req, res, next) {
  res.send('Successfully logged in.');
});

app.get('/error', function(req, res, next) {
  res.send("Error logging in.");
});

app.get('/', function(req, res, next) {
  res.sendfile('./html/auth.html');
});

http.createServer(app).listen(app.get('port'), function() {
  console.log('Express server listening on port ' + app.get('port'));
});

Now, simply restart the node server, refresh the browser, and click on the Sign in with Facebook link.

Implementing GitHub Authentication

The process for adding GitHub authentication is quite similar to what we did for Facebook. First, install the passport-github' module using the commandnpm install passport-github`.

Go to GitHub, and click Account Settings in the upper right corner. Next click on the Applications link, and create a new app. Pay special attention to your Client ID and Client Secret. Set the Homepage URL to http://localhost:3000/ and the Authorization callback URL to http://localhost:3000/auth/github/callback. The following screenshot shows how the application should be configured.

GitHub App Setup

In the Express server, we need to configure the GitHub strategy, and set up routes and callbacks, just like we did for Facebook authentication.

passport.use(new GitHubStrategy({
  clientID: GITHUB_CLIENT_ID,
  clientSecret: GITHUB_CLIENT_SECRET,
  callbackURL: 'http://localhost:3000/auth/github/callback'
}, function(accessToken, refreshToken, profile, done) {
  process.nextTick(function() {
    return done(null, profile);
  });
}));

app.get('/auth/github', passport.authenticate('github'));

app.get('/auth/github/callback', passport.authenticate('github', {
  successRedirect: '/success',
  failureRedirect:'/error'
}));

Now, simply restart the node server and try logging in using the GitHub link.

Conclusion

In this tutorial, we saw how Passport made the task of authentication quite simple. Implementing Google and Twitter authentication follows a nearly identical pattern. The reader is encouraged to implement these using the passport-google and passport-twitter modules. In the meantime, the code for this app is available on GitHub.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • mohsen_shafiee

    please add local Authentication

  • andrewvijay

    good post jay!

    • http://www.techillumination.in Jay

      thnks Andrewvijay :)

  • Wibby

    Out of every tutorial I’ve tried to follow to get authentication to work with my project, your’s is the only one that worked. YES! I’d like to see a local version of this too. (:

    • http://www.techillumination.in Jay

      thnks Wibby :)

  • Luís Miranda

    Hi.

    Thanks for sharing.

    When i try to add localhost in App Domains, facebook gives the following warning: “To-level domains are not allowed”.

    Does anyone knows what the problem is?

    Thanks

    • Luís Miranda

      I think i don’t need App Domains anyway… or do i?

  • alex

    Is there some way to redirect back after logging in to the the page where I started the facebook authentication?

  • Muhammad Saleh

    It would be great if you can update your tutorial for Express 4
    as it gives me an error when using
    app.use(app.router);

    It tells me that app.router is deprecated