Taking Toddler Steps with Node.js – Passport

May 15th, 2012

Recently I added Twitter authentication to TrackMyRun using a library called Passport. I was pretty impressed how smooth this all went as I completely neglected all security concerns from the get go, which is definitely not recommended by the way. For this post I’ll walk you through the process of setting up Passport for Express using Twitter OAuth authentication.

Passport is actually the core library which provides support for OpenId and OAuth authentication. Instead of being one single monolithic library, Passport uses strategies that support authentication directly with specific OpenId/OAuth providers.

So in order to get up and running, we need to install passport as well as passport-twitter for Twitter OAuth authentication. After we install these modules using npm, we can start by configuring the Twitter strategy.

var express = require('express'),
    passport = require('passport'),
    TwitterStrategy = require('passport-twitter').Strategy;

var users = [];

passport.use(new TwitterStrategy({
        consumerKey: 'twitter-app-consumer-key',
        consumerSecret: 'twitter-app-consumer-secret',
        callbackURL: "http://test.passport-twitter.com:3000/auth/twitter/callback"
    },
    function(token, tokenSecret, profile, done) {
        var user = users[profile.id] || 
                   (users[profile.id] = { id: profile.id, name: profile.username });
        done(null, user);
    }
));

 

The strategy must be configured by providing the consumer key and consumer secret as well as the callback URL. I’m not going too much in depth on how OAuth works. Make sure to check out the Twitter for developers website on how to configure an application that uses the Twitter API.

Besides adding the strategy for Twitter, we also specified a callback function. In this callback, we’re supposed to find and verify a user that matches a specified set of credentials. Usually we have some code here that checks to see if the specified user exists in a database of some sort. In order not to clutter this example, I used a simple array here instead.

If we can find the requested user in our data store, we need to invoke done() to supply the Passport with the user.

done(null, user);

When the user cannot be found, we can simply pass false instead of a user object.

done(null, false);

In our example we always ensure that the specified credentials match a particular user object. Next we need to configure the Passport middleware for initialization and session management.

application.configure(function() {
    application.use(express.bodyParser());
    application.use(express.methodOverride());
    application.use(express.cookieParser());
    application.use(express.session( { secret: '498f99f3bbee4ae3a075eada02488464' } ));
    application.use(passport.initialize());
    application.use(passport.session());
    application.use(application.router);
    application.use(express.errorHandler({ showStack: true, dumpExceptions: true }));
    application.set('view engine', 'jade');
});

Please note that the express.session() middleware needs be called before passport.session(). Next we add the routes necessary for authenticating requests and handling the token callback.

application.get('/auth/twitter', passport.authenticate('twitter'));

application.get('/auth/twitter/callback', 
    passport.authenticate('twitter', 
        { successRedirect: '/', 
          failureRedirect: '/auth/twitter' }));

 

Last but not least we also need to declare a serializeUser/deserializeUser callback function. These are necessary for supporting login sessions.

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

passport.deserializeUser(function(id, done) {
    var user = users[id];
    done(null, user);
});

Instead of reading the requested user objects from the data store, we simply use the array that we incorporated earlier.

That’s basically the thing. We can add other authentication providers by simply configuring more strategies. Have a look at the full source code of this example and try to get it up and running.

Until next time.

  • Larry

    Is trackmyrun a public site? What is the URL. Thank you :)

    • JanVanRyswyck

      It’s non a public website as I’m the only one that can login at the moment. However, it is open-source so it should not be that difficult to run locally or set it up in the cloud. I should set up a wiki page for that ;-).