Over a million developers have joined DZone.

OAuth Authentication with Passport.js and Integration with Jade

· Web Dev Zone

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

Again, we’re talking about a technology used on www.parkuik.com (aren’t you registered yet? ;P)

Although simple registration via username and password is really important (which I’ll do in the near future), nowadays it’s more important to give users website access through OAuth providers such as Facebook or Twitter. There are tons of them, but of course, these two are the best known.

First of all, I must say that there are two major options on node.js world to include OAuth log in: Passport.js and Everyauth. These two are valid options, but I must say that I started with everyauth months ago and it was very buggy. I don’t know how it is right now, but if I have to tell you one of them to use, I’ll go with passport.js (which includes OAuth and simple registration).

So, first of all, you need to register your application to all of OAuth providers you want to use. This is different for each provider, so just go to its website and try it. It’s pretty simple =).

Once you’ve done that, you’ll have two keys. Depending on the OAuth provider they’ll be called different. Facebook uses appId and appSecret, Twitter uses consumerKey and consumerSecret, Github uses appId and appSecret, etc.

Now, install passport on your project:

npm install passport

This is not the only thing you have to install. For every oauth provider you want to work with, you must install its module. For Facebook, passport-Facebook, for Twitter, passport-Twitter, etc.

npm instal passport-twitter
npm instal passport-facebook

First of all, I’m used to include these oauth token keys or however-you-want-to-call-them, in a separate file avoiding mixing it with all the app:

var ids = {
  fb: {
    appId: '...',
    appSecret: '...'
  },
  twit: {
    consumerKey: '...',
    consumerSecret: '...'
  },
  github: {
    appId: '...',
    appSecret: '...'
  },
  instagram: {
    clientId: '...',
    clientSecret: '...'
  }
}

You must configure your app and routes to use OAuth. This must be done on the main file, which I usually call app.js. This could be done this way (I’m posting only the Twitter solution because other providers are done the same way):

var conf = require('./config/oauth_providers.js')
app.configure(function(){
  ...
  app.use(express.session({secret: "ihauyd6tqwueuhet7dwqyqwhiwqhuyiod"}));
  app.use(passport.initialize());
  app.use(passport.session());
});
passport.use(new TwitterStrategy({
    consumerKey: conf.twit.consumerKey,
    consumerSecret: conf.twit.consumerSecret,
    callbackURL: callbackURL('twitter')
  },
  function(token, tokenSecret, profile, done) {
    var User = mongoose.model('User');
    User.findOne({providerId: profile.id},
      function(err, user) {
        if (!err && user != null) {
          var ObjectId = mongoose.Types.ObjectId;
          User.update({"_id": user["_id"]}, { $set: {lastConnected: new Date()} } ).exec();
        } else {
          var userData = new User({
            provider: profile.provider,
            providerUsername: profile.username,
            providerId: profile.username + ":" + profile.id,
            created: Date.now(),
            oauthToken: token,
            username: profile.displayName,
            profilePicture: 'https://api.twitter.com/1/users/profile_image?screen_name=' + profile.username +'&size=bigger'
          });
          userData.save(function(err) {
            if (err) console.log(err);
            else console.log('Saving user...');
          });
        }
      }
      );
      var user = { id: profile.id, name: profile.username });
      done(null, user);
  }
));

And now we have to define our callbacks and routes. This includes all the work to insert users and get them from database.

app.get('/auth/twitter', passport.authenticate('twitter'), {scope: 'email'});
app.get('/auth/facebook', passport.authenticate('facebook', {scope: 'email'}));
app.get('/auth/twitter/callback',
  passport.authenticate('twitter', { successRedirect: '/main',
                                    failureRedirect: '/auth/twitter'})
);
app.get('/auth/facebook/callback',
  passport.authenticate('facebook', { successRedirect: '/main',
                                    failureRedirect: '/auth/facebook'})
);
app.get('/logout', isAuthenticated, function(req, res) {
  req.logOut();
  res.redirect('/');
});

Here I’m using Mongoose to work with MongoDB database, but of course, you could use whatever you want.

As you can see in routes defined by express, /logout is used to log the user out. So, just put a link to logout, and it’ll be done.

Other things you can do? define a “isAuthenticated” function (you must come up with a solution that works for you) and use it this way to access protected resources:

app.put('/parkings/:id', isAuthenticated, routes.parkings.putParking);

Or you may want to define herlpers to use variables on your jade templates:

var helpers = {};
helpers.auth = function(req, res) {
    var map = {};
    map.isAuthenticated = req.isAuthenticated();
    map.user = req.user;
    return map;
}
app.dynamicHelpers(helpers);

If you want to use it on a Jade template, just call it this way:

#{auth.isAuthenticated}

Pretty simple!

Do you know any other solutions? more efficient?

Thanks!

Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

Topics:

Published at DZone with permission of Javier Manzano, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}