Skip to content

Requiring authentication

mde edited this page Oct 19, 2012 · 9 revisions

Use a before-filter to require authentication for all controller actions in your app.

You can use the except property to exempt certain actions from the filter and the only property to require it only for certain actions.

If you're going to do any sort of I/O during the filter, you have to flag it with async: true, and call a complete callback when you're done to allow the action to run after the filter.

Example

This example requires the requireAuthorization function to run before all actions except the "authorize" and "healthcheck" actions. It looks for a session with an OAuth access token, and if it doesn't find one send the user into an OAuth authentication flow.

This is just an example, but the OAuth flow would be similar for any provider who does OAuth2.

/**
  @description Asynchronous before-filter that ensures a user
  has OAuth2-authorized the app, and has a valid access-token.
*/
var requireAuthorization = function (complete) {
  var self = this
    , opts
    , config = geddy.config
    , app = config.clientApp
    , code
    , req
    , url;

  // If there's no session with an access-token
  if (!this.session.get('accessToken')) {
    code = this.params.code;
    // Have code, get access_token
    if (code) {
      url = config.oauthProvider +
          '/oauth2/access_token.json?client_id=' + app.id +
          '&client_secret=' + app.secret + '&code=' + code;
      // Grab the OAuth2 access-token
      geddy.request({url: url}, function (err, data) {
        var token = data.access_token.token;

        // Prevent session-fixation
        self.session.reset();

        // Save the access-token for all API-requests
        self.session.set('accessToken', token);

        self.redirect('/');
        complete();
      });
    }
    // No code, do OAuth2 hokey-pokey
    else {
      this.redirect('/authorize');
      complete();
    }
  }
  // We have a session with an access-token
  else {
    // Do any other stuff you might need to do before
    // running the action (e.g., do API calls to set up
    // user-data)
    complete();
  }
};

var Application = function () {
  this.protectFromForgery();
  this.before(requireAuthorization, {
    except: ['authorize', 'healthcheck']
  , async: true
  });

};

exports.Application = Application;

(The protectFromForgery method prevents cross-site requests for PUT/POST/DELETE. To use this feature, you have to run the geddy secret command-line command to generate a secret for your app.)

Below is an example of a Main controller that could implement the '/authorize' endpoint that routes your users through the OAuth flow of your chosen provider:

var Main = function () {
  this.index = function (req, resp, params) {
    // Do main app stuff
  };

  this.authorize = function (req, resp, params) {
    var config = geddy.config
      , app = config.clientApp
      , redir = encodeURIComponent(config.hostname + app.callbackURL);
    this.redirect(config.oauthProvider + '/dialog/oauth?client_id=' +
        app.id + '&redirect_uri=' + redir);
  };

  this.healthcheck = function () {
    this.respond('ok');
  };

};

exports.Main = Main;