Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js: Connect-Auth VS. EveryAuth

Tags:

node.js

Can anyone give a good comparison between: https://github.com/ciaranj/connect-auth and https://github.com/bnoguchi/everyauth

Which seem to be the only options for express/connect

like image 922
balupton Avatar asked Apr 23 '11 15:04

balupton


2 Answers

I'm the author of everyauth.

I wrote everyauth because I found using connect-auth lacking in terms of:

  1. Easy and powerful configuration

    To get particular, one area where it was lacking in terms of configurability was setting facebook's "scope" security settings dynamically.

  2. Good debugging support

    I found connect-auth not-so-straightforward to debug in terms of pinpointing the part of the auth process was failing. This is mostly due to the way that connect-auth sets up its nested callbacks.

With everyauth, I tried to create a system that solved the issues I ran into with connect-auth.

  • On configuration - every everyauth auth module is defined as a series of steps and configurable parameters. As a result, you have surgery-like precision over what parameters (e.g., hostname, callback url, etc.) or steps (e.g., getAccessToken, addToSession) you want altered. With connect-auth, if you want to change one thing besides the few built in configurable parameters each auth strategy provides, you have to re-write the entire this.authenticate function that defines the logic for all of that strategy. In other words, it has less precision of configurability than everyauth. In other cases, you cannot use connect-auth, as is -- for example, achieving dynamic facebook "scope" configurability - i.e., asking users for more facebook permissions progressively as they get to portions of your app that require more permissions.

    In addition to configurable steps and parameters, you can also take advantage of everyauth's auth module inheritance. All modules inherit prototypically from the everymodule auth module. All OAuth2-based modules inherit from the oauth2 module. Let's say you want all oauth2 modules to behave differently. All you need to do is modify the oauth2 auth module, and all oauth2-based modules will inherit that new behavior from it.

  • On debugging - everyauth, in my opinion, has better debugging visibility because of the very fact that it segments each module explicitly into the steps of which it is composed. By setting

    everyauth.debug = true; 

    you get output of what steps in the authentication process have completed and which ones have failed. You also have granular control over how long each step in each auth strategy has before it times out.

  • On extensibility - I designed everyauth to maximize code re-use. As mentioned before, all modules inherit prototypically from the everymodule auth module. This means that you can achieve very modular systems while at the same time having fine grained control in terms of over-riding a specific step from an ancestor module. To see how easy it is to extend everyauth with your own auth module, just take a look at any of the specific auth modules in everyauth's source.

  • On readability - I find everyauth source easier to read in terms of what is going on. With connect-auth, I found myself jumping around the several files to understand under what contexts (i.e., during what steps, in everyauth parlance) each nested callback configured by a strategy was running. With everyauth, you know exactly what piece of logic is associated with which context (aka step). For instance, here is the code describing what happens when an oauth2 provider redirects back to your service:

    .get('callbackPath',                                                                                                                                                     'the callback path that the 3rd party OAuth provider redirects to after an OAuth authorization result - e.g., "/auth/facebook/callback"')                        .step('getCode')     .description('retrieves a verifier code from the url query')                                                                                                        .accepts('req res')       .promises('code')                                                            .canBreakTo('authCallbackErrorSteps')   .step('getAccessToken')     .accepts('code')     .promises('accessToken extra')                                                                                                                                    .step('fetchOAuthUser')     .accepts('accessToken')                                                                                                                                             .promises('oauthUser')   .step('getSession')     .accepts('req')     .promises('session')   .step('findOrCreateUser')                                                                                                                                             .accepts('session accessToken extra oauthUser')                                                                                                                     .promises('user')   .step('compile')     .accepts('accessToken extra oauthUser user')     .promises('auth')   .step('addToSession')     .accepts('session auth')                                                                                                                                            .promises(null)   .step('sendResponse')     .accepts('res')     .promises(null) 

    Without needing to explain how this works, its pretty straightforward to see what an oauth2 strategy does. Want to know what getCode does? The source again is very straightforward:

    .getCode( function (req, res) {   var parsedUrl = url.parse(req.url, true);   if (this._authCallbackDidErr(req)) {     return this.breakTo('authCallbackErrorSteps', req, res);   }   return parsedUrl.query && parsedUrl.query.code; }) 

    Compare this all to connect-auth's facebook code, which for me at least, took more time than I thought it should have to figure out what is getting executed when. This is mostly because of the way in which the code is spread across files and because of the use of a single authenticate method and nested callbacks to define authentication logic (everyauth uses promises to break down the logic into easily digestible steps):

    that.authenticate= function(request, response, callback) {   //todo: makw the call timeout ....   var parsedUrl= url.parse(request.url, true);   var self= this;   if( parsedUrl.query && parsedUrl.query.code  ) {     my._oAuth.getOAuthAccessToken(parsedUrl.query && parsedUrl.query.code ,        {redirect_uri: my._redirectUri}, function( error, access_token, refresh_token ){          if( error ) callback(error)          else {            request.session["access_token"]= access_token;            if( refresh_token ) request.session["refresh_token"]= refresh_token;              my._oAuth.getProtectedResource("https://graph.facebook.com/me", request.session["access_token"], function (error, data, response) {                if( error ) {                  self.fail(callback);                }else {                  self.success(JSON.parse(data), callback)                }              })          }     });   }   else {      request.session['facebook_redirect_url']= request.url;      var redirectUrl= my._oAuth.getAuthorizeUrl({redirect_uri : my._redirectUri, scope: my.scope })      self.redirect(response, redirectUrl, callback);    } } 

A few other differences:

  • everyauth supports traditional password-based authentication. connect-auth, as of this writing, does not.
  • The foursquare and google support in connect-auth is based on the older OAuth1.a spec. everyauth's foursquare and google modules are based on their implementations of the newer OAuth2 spec.
  • OpenId support in everyauth.
  • everyauth's documentation is much more comprehensive than connect-auth's.

Finally, to comment on Nathan's answer which was unsure about everyauth support for multiple providers at the same time, everyauth does support multiple, concurrent providers. The README on everyauth's github page provides instructions about how to use everyauth to achieve this.

To conclude, I think choice of libraries depends on the developer. I, and others, find everyauth more powerful from their point of view. As Nathan's answer illustrates, yet others find connect-auth more tuned in to their preferences. Whatever your choice, I hope this write-up about why I wrote everyauth helps you in your decision.

like image 199
Brian Noguchi Avatar answered Sep 19 '22 15:09

Brian Noguchi


Both libraries are pretty close in feature sets, especially in terms of supported providers. connect-auth provides support out-of-the-box to make your own oAuth providers, so that could well help you out if you’re going to need that sort of thing.

The main thing I’ve noted between the two is that I find connect-auth much cleaner with the way it creates and accepts the middleware; you only have to look at the amount of pre-configuration required for the middleware in everyauth to see that it's going to get messy.

Another thing that isn't clear is whether everyauth supports multiple providers at the same time; with connect-auth, it seems possible/more straightforward, though I’ve yet to try this myself.

like image 25
Nathan Kleyn Avatar answered Sep 18 '22 15:09

Nathan Kleyn