diff --git a/lib/modules/everymodule.js b/lib/modules/everymodule.js index 32ec5bd6..b3e0be3a 100644 --- a/lib/modules/everymodule.js +++ b/lib/modules/everymodule.js @@ -33,6 +33,8 @@ function EveryModule () { , findUserById: 'function for fetching a user by his/her id -- used to assign to `req.user` - function ( [req], userId, callback) where function callback (err, user)' , performRedirect: 'function for redirecting responses' , userPkey: 'identifying property of the user; defaults to "id"' + , isMobile: 'function used to determine if request is performed by a mobile browser - ' + + 'function(req) - truthy return value should be used by submodule to redirect to mobile version of login pages' }) .get('logoutPath') .step('handleLogout') @@ -51,6 +53,10 @@ function EveryModule () { res.end(); }); + this.isMobile( function() { + return false; + }); + this.moduleTimeout(10000); this.moduleErrback( function (err, seqValues) { if (! (err instanceof Error)) { diff --git a/lib/modules/facebook.js b/lib/modules/facebook.js index 9857cfee..92e71cd0 100644 --- a/lib/modules/facebook.js +++ b/lib/modules/facebook.js @@ -11,7 +11,7 @@ oauthModule.submodule('facebook') .apiHost('https://graph.facebook.com/v2.0') .oauthHost('https://graph.facebook.com/v2.0') - .authPath('https://www.facebook.com/v2.0/dialog/oauth') + .authPath('/dialog/oauth') .entryPath('/auth/facebook') .callbackPath('/auth/facebook/callback') @@ -20,6 +20,11 @@ oauthModule.submodule('facebook') return this._scope && this.scope(); }) + .buildAuthorizePath( function (isMobile) { + var host = isMobile ? 'https://m.facebook.com/v2.0' : 'https://www.facebook.com/v2.0'; + return host + this.authPath(); + }) + .authCallbackDidErr( function (req) { var parsedUrl = url.parse(req.url, true); return parsedUrl.query && !!parsedUrl.query.error; @@ -72,9 +77,11 @@ oauthModule.submodule('facebook') }); fb.mobile = function (isMobile) { - if (isMobile) { - this.authPath('https://m.facebook.com/v2.0/dialog/oauth'); - } + // backward compatibility only + // it's better if application define isMobile function to handle this on a per request basis + this.isMobile(function() { + return isMobile; + }); return this; }; diff --git a/lib/modules/linkedin.js b/lib/modules/linkedin.js index 85b933d8..fd323ea5 100644 --- a/lib/modules/linkedin.js +++ b/lib/modules/linkedin.js @@ -32,8 +32,9 @@ oauthModule.submodule('linkedin') .entryPath('/auth/linkedin') .callbackPath('/auth/linkedin/callback') - .redirectToProviderAuth( function (res, token) { - this.redirect(res, 'https://www.linkedin.com' + this.authorizePath() + '?oauth_token=' + token); + .buildAuthorizePath( function (isMobile) { + var host = isMobile ? 'http://touch.www.linkedin.com' : 'https://www.linkedin.com'; + return host + this.authorizePath(); }) .fetchOAuthUser( function (accessToken, accessTokenSecret, params) { diff --git a/lib/modules/oauth.js b/lib/modules/oauth.js index b35491cb..7bc06657 100644 --- a/lib/modules/oauth.js +++ b/lib/modules/oauth.js @@ -19,6 +19,8 @@ everyModule.submodule('oauth') , redirectPath: 'Where to redirect to after a failed or successful OAuth authorization' , convertErr: '(DEPRECATED) a function (data) that extracts an error message from data arg, where `data` is what is returned from a failed OAuth request' , authCallbackDidErr: 'Define the condition for the auth module determining if the auth callback url denotes a failure. Returns true/false.' + , buildAuthorizePath: 'function that returns the host and path to which you direct a visitor to login ' + + 'function(isMobile) - authorizePath is automatically appended' }) .definit( function () { this.oauth = new OAuth( @@ -41,7 +43,7 @@ everyModule.submodule('oauth') .promises(null) .step('redirectToProviderAuth') .description('sends the user to authorization on the OAuth provider site') - .accepts('res token') + .accepts('req res token') .promises(null) .get('callbackPath', @@ -142,12 +144,12 @@ everyModule.submodule('oauth') _provider.token = token; _provider.tokenSecret = tokenSecret; }) - .redirectToProviderAuth( function (res, token) { + .redirectToProviderAuth( function (req, res, token) { // Note: Not all oauth modules need oauth_callback as a uri query parameter. As far as I know, only readability's // module needs it as a uri query parameter. However, in cases such as twitter, it allows you to over-ride // the callback url settings at dev.twitter.com from one place, your app code, rather than in two places -- i.e., // your app code + dev.twitter.com app settings. - var redirectTo = this._oauthHost + this._authorizePath + '?oauth_token=' + token; + var redirectTo = this._buildAuthorizePath(this._isMobile(req)) + '?oauth_token=' + token; if (this._sendCallbackWithAuthorize) { redirectTo += '&oauth_callback=' + this._myHostname + this._callbackPath; } @@ -255,7 +257,10 @@ oauth .handleAuthCallbackError( function (req, res, next) { next(new Error("You must configure handleAuthCallbackError in this module")); }) - .sendCallbackWithAuthorize(true); + .sendCallbackWithAuthorize(true) + .buildAuthorizePath(function() { + return this._oauthHost + this._authorizePath; + }); oauth.moreRequestTokenQueryParams = {}; oauth.cloneOnSubmodule.push('moreRequestTokenQueryParams'); diff --git a/lib/modules/oauth2.js b/lib/modules/oauth2.js index 0cc02834..7ce04792 100644 --- a/lib/modules/oauth2.js +++ b/lib/modules/oauth2.js @@ -19,9 +19,9 @@ everyModule.submodule('oauth2') , oauthHost: 'the host for the OAuth provider' , appId: 'the OAuth app id provided by the host' , appSecret: 'the OAuth secret provided by the host' - , authPath: "the path on the OAuth provider's domain where " + + , authPath: "the path on the OAuth provider's domain where " + "we direct the user for authentication, e.g., /oauth/authorize" - , accessTokenPath: "the path on the OAuth provider's domain " + + , accessTokenPath: "the path on the OAuth provider's domain " + "where we request the access token, e.g., /oauth/access_token" , accessTokenHttpMethod: 'the http method ("get" or "post") with which to make our access token request' , customHeaders: 'any cusomt headers required in the access token request' @@ -30,8 +30,11 @@ everyModule.submodule('oauth2') 'the access token endpoint in the request body' , myHostname: 'e.g., http://local.host:3000 . Notice no trailing slash' , alwaysDetectHostname: 'does not cache myHostname once. Instead, re-detect it on every request. Good for multiple subdomain architectures' + , redirectPath: 'Where to redirect to after a failed or successful OAuth authorization' , convertErr: '(DEPRECATED) a function (data) that extracts an error message from data arg, where `data` is what is returned from a failed OAuth request' , authCallbackDidErr: 'Define the condition for the auth module determining if the auth callback url denotes a failure. Returns true/false.' + , buildAuthorizePath: 'function that returns the host and path to which you direct a visitor to login ' + + 'function(isMobile) - authPath is automatically appended' }) // Declares a GET route that is aliased @@ -94,10 +97,7 @@ everyModule.submodule('oauth2') client_id: this._appId , redirect_uri: this._myHostname + this._callbackPath } - , authPath = this._authPath - , url = (/^http/.test(authPath)) - ? authPath - : (this._oauthHost + authPath) + , url = this._buildAuthorizePath(this._isMobile(req)) , additionalParams = this.moreAuthQueryParams , param; @@ -269,6 +269,13 @@ oauth2 .handleAuthCallbackError( function (req, res, next) { next(Error("You must configure handleAuthCallbackError in this module")); }) + .buildAuthorizePath( function() { + // by default we ignore isMobile value + var authPath = this._authPath; + return (/^http/.test(authPath)) + ? authPath + : (this._oauthHost + authPath); + }); // Add or over-write existing query params that // get tacked onto the oauth authorize url. diff --git a/lib/modules/tripit.js b/lib/modules/tripit.js index 94a6a8ef..827061aa 100644 --- a/lib/modules/tripit.js +++ b/lib/modules/tripit.js @@ -7,12 +7,9 @@ oauthModule.submodule('tripit') .oauthHost('https://api.tripit.com') .entryPath('/auth/tripit') .callbackPath('/auth/tripit/callback') - .redirectToProviderAuth( function (res, token) { - var redirectTo = 'https://www.tripit.com' + this.authorizePath() + '?oauth_token=' + token; - if (this.sendCallbackWithAuthorize()) { - redirectTo += '&oauth_callback=' + this.myHostname() + this.callbackPath(); - } - this.redirect(res, redirectTo); + .buildAuthorizePath( function (isMobile) { + var host = isMobile ? 'https://m.tripit.com' : 'https://www.tripit.com'; + return host + this.authorizePath(); }) .fetchOAuthUser( function (accessToken, accessTokenSecret, params) { var promise = this.Promise();