Node.js — Getting oAuth Up and Running Using Express.js and Mongoose

Stamped: 10 Oct 2011 | Show comments

Getting Started

If you're interested in how to incorporate this into railwayjs, see this other article instead. I normally use coffeescript, but for the purposes of this article, I converted it to javascript. For the impatient, this project can be found in my github repos.

Let's assume our app.js/server.js looks like this:

var express = require('express');
var app = express.createServer();

app.get('/', function(req, res){
  res.send('hello world');
});

app.configure(function() {
  app.set('views', __dirname + '/app/views');
  app.set('view engine', 'jade');
});

app.listen(3001);

Now, getting oAuth up and running can be easy, but you have to make sure you have mongodb up and running first, since we're using mongoose-auth. You could very well use everyauth, which mongoose-auth is based upon, though it would require a little more effort if you were to change to another database. This is pretty easy: in Ubuntu, you can just apt-get install mongodb, or in osx, brew install mongodb;. If you need to install homebrew for OSX, /usr/bin/ruby -e "$(curl -fsSL https://raw.github.com/gist/323731)".

Working with MongoDB

Let's connect to mongo:

var mongoose = require('mongoose')
  , Schema = mongoose.Schema
  , ObjectId = mongoose.SchemaTypes.ObjectId;
  
mongoose.connect('mongodb://localhost/example'); 

Incorporate mongoose-auth

To get this working, we have to add the following to our app.js:

var conf = require('./config/oauth_providers');
var UserSchema = new Schema({})
    , User;
var mongooseAuth = require('mongoose-auth');

UserSchema.plugin(mongooseAuth, {
  everymodule: {
    everyauth: {
      User: function() {
        return User;
      }
    }
  },
  facebook: {
    everyauth: {
      myHostname: 'http://local.host:3001',
      appId: conf.fb.appId,
      appSecret: conf.fb.appSecret,
      redirectPath: '/'
    }
  },
  twitter: {
    everyauth: {
      myHostname: 'http://local.host:3001',
      consumerKey: conf.twit.consumerKey,
      consumerSecret: conf.twit.consumerSecret,
      redirectPath: '/'
    }
  },
  github: {
    everyauth: {
      myHostname: 'http://local.host:3001',
      appId: conf.github.appId,
      appSecret: conf.github.appSecret,
      redirectPath: '/'
    }
  }
});

mongoose.model('User', UserSchema);

mongoose.connect('mongodb://localhost/example');

User = mongoose.model('User');

The configuration for this file resides in a different folder, I made a config folder and put the oauth_providers.js file in there, it looks like this:

module.exports = {
  fb: {
    appId: '111565172259433',
    appSecret: '85f7e0a0cc804886180b887c1f04a3c1'
  },
  twit: {
    consumerKey: 'JLCGyLzuOK1BjnKPKGyQ',
    consumerSecret: 'GNqKfPqtzOcsCtFbGTMqinoATHvBcy1nzCTimeA9M0'
  },
  github: {
    appId: '11932f2b6d05d2a5fa18',
    appSecret: '2603d1bc663b74d6732500c1e9ad05b0f4013593'
  },
  instagram: {
    clientId: 'be147b077ddf49368d6fb5cf3112b9e0',
    clientSecret: 'b65ad83daed242c0aa059ffae42feddd'
  },
};

NOTE: these keypairs really shouldn't be made public, but they exist in the mongoose-auth repo, so you can test using them. This also assumes you have something setup in /etc/hosts to map local.host to 127.0.0.1, example: 127.0.0.1 local.host

In addition, we have to configure express a little differently:

app.configure(function() {
  app.set('views', __dirname + '/app/views');
  app.set('view engine', 'jade');
  app.use(express.bodyParser());
  app.use(express.cookieParser());
  app.use(express.session({secret: 'secret'}));
  app.use(mongooseAuth.middleware());
});

mongooseAuth.helpExpress(app);

The above sets up cookies, adds a session key, hooks into mongooseAuth to the app, and exposes everyauth's routes to express' views.

Logging in

Now, just by visiting http://local.host:3000/auth/twitter, for example, and logging in, you'll be redirected back to the homepage. To check to make sure it's working, we have to add some views, make a folder called views and place the following in it named index.jade

- var items = ["facebook", "github", "twitter", "instagram"]
- if (!everyauth.loggedIn)
  h2 Not Authenticated
  each item in items
   a(href='/auth/' + item)
     span Connect with <span style="text-transform: capitalize">!{item}</span><br />

- else
  h2 Authenticated
  #user-id Logged in with `user.id` #{user.id} - aka `everyauth.user.id` #{everyauth.user.id}
  - if (everyauth.facebook)
    h3 Facebook User Data
    p= JSON.stringify(everyauth.facebook.user)
  - if (everyauth.twitter)
    h3 Twitter User Data
    p= JSON.stringify(everyauth.twitter.user)
  - if (everyauth.github)
    h3 GitHub User Data
    p= JSON.stringify(everyauth.github.user)
  - if (everyauth.instagram)
    h3 Instagram User Data
    p= JSON.stringify(everyauth.instagram.user)
  h3
    a(href='/logout') Logout

And don't forget to change the route, to

app.get('/', function(req, res){
    res.render('index');
});

And if you've been following, you'll see that all the twitter metadata is displayed. You're done! There's a lot of other things you can do, like being able to link each different account, whether or not to remember the user, and if anyone needs help with that, I can show you how to do it.

This project can be found in my github repo, expressjs & oauth.

tags: nodejs, oauth, railwayjs, expressjs
recent entries
Rails — A faster way for next and previous links on a post, article, or any model
The awkward things Siri says
Node.js — Getting oAuth Up and Running Using Express.js and Mongoose
Node.js — Getting oAuth Up and Running Using Express.js, Railway.js and Mongoose
Migrating from Rails 3.1 RC4 to RC5 using Heroku's Cedar Stack (also compass, unicorn, and sendgrid)
Random Freeze Fix for GTX 460 in 10.6 (osx86)
Wasted on Steam - an analytic tool for the Steam platform
Rails 3.1 — SQL logging to STDOUT during testing (with rspec, test::unit, or cucumber)
Rails 3.1 — Using ERB/HAML/etc within a Coffeescript JS file
Rails 3.1 — 'load_missing_contant': Expected ... to define ... (LoadError)
View the entire archive of articles