From 8dabfca06719e5515bc5f92e2071f1bacdf13cf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Cl=C3=A9riot?= Date: Mon, 28 Aug 2017 18:24:14 +0200 Subject: [PATCH] Add useAuthorizationHeaderForToken option If this option is set to true, we request a token by sending client_id and client secret with an Authorization header instead of url params --- lib/strategy.js | 13 ++++++++---- lib/utils.js | 53 ++++++++++++++++++++++++++++++++++++++++++++++++- package.json | 1 + 3 files changed, 62 insertions(+), 5 deletions(-) diff --git a/lib/strategy.js b/lib/strategy.js index 90c0a0e..2689456 100644 --- a/lib/strategy.js +++ b/lib/strategy.js @@ -28,7 +28,9 @@ function Strategy(options, verify) { passport.Strategy.call(this); this.name = 'openidconnect'; this._verify = verify; - + + this._useAuthorizationHeaderForToken = options.useAuthorizationHeaderForToken || false; + // TODO: What's the recommended field name for OpenID Connect? this._identifierField = options.identifierField || 'openid_identifier'; this._scope = options.scope; @@ -48,6 +50,8 @@ function Strategy(options, verify) { } else { this.configure(require('./setup/dynamic')(options)); } + + OAuth2 = utils.fixOAuthLib(OAuth2) } /** @@ -88,7 +92,8 @@ Strategy.prototype.authenticate = function(req, options) { var callbackURL = meta.callbackURL; var oauth2 = self._getOAuth2Client(meta); - + + //Original method overrided by utils.fixOAuthLib oauth2.getOAuthAccessToken(code, { grant_type: 'authorization_code', redirect_uri: callbackURL }, function(err, accessToken, refreshToken, params) { if (err) { return self.error(new InternalOAuthError('failed to obtain access token', err)); } @@ -246,7 +251,7 @@ Strategy.prototype.authenticate = function(req, options) { } } // onProfileLoaded }); // self._shouldLoadUserProfile - }); // oauth2.getOAuthAccessToken + }, self._useAuthorizationHeaderForToken); // oauth2.getOAuthAccessToken } // loaded var state = req.query.state; @@ -413,7 +418,7 @@ Strategy.prototype._shouldLoadUserProfile = function(issuer, subject, done) { Strategy.prototype._getOAuth2Client = function (config) { return new OAuth2(config.clientID, config.clientSecret, - '', config.authorizationURL, config.tokenURL); + '', config.authorizationURL, config.tokenURL); } /** diff --git a/lib/utils.js b/lib/utils.js index f374976..a5c827f 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,5 +1,5 @@ var crypto = require('crypto'); - +var querystring= require('querystring') /** * Reconstructs the original URL of the request. @@ -73,3 +73,54 @@ exports.uid = function(len) { .toString('base64') .slice(0, len); }; + +/** + * Override getOAuthAccessToken to use an Authorization header instead of sending + * client_id and client_secret in the url + */ +exports.fixOAuthLib = function(lib) { + lib.prototype.getOAuthAccessToken = function(code, params, callback, useAuthorization) { + var useAuthorization = useAuthorization || false; + + var params= params || {}; + var codeParam = (params.grant_type === 'refresh_token') ? 'refresh_token' : 'code'; + params[codeParam]= code; + + var post_data= querystring.stringify( params ); + var post_headers= { + 'Content-Type': 'application/x-www-form-urlencoded' + }; + + if(useAuthorization) { + post_headers['Authorization'] = 'Basic ' + new Buffer(this._clientId + ':' + this._clientSecret).toString('base64') + } + else { + params['client_id'] = this._clientId; + params['client_secret'] = this._clientSecret; + } + + this._request("POST", this._getAccessTokenUrl(), post_headers, post_data, null, function(error, data, response) { + if( error ) callback(error); + else { + var results; + try { + // As of http://tools.ietf.org/html/draft-ietf-oauth-v2-07 + // responses should be in JSON + results= JSON.parse( data ); + } + catch(e) { + // .... However both Facebook + Github currently use rev05 of the spec + // and neither seem to specify a content-type correctly in their response headers :( + // clients of these services will suffer a *minor* performance cost of the exception + // being thrown + results= querystring.parse( data ); + } + var access_token= results["access_token"]; + var refresh_token= results["refresh_token"]; + delete results["refresh_token"]; + callback(null, access_token, refresh_token, results); // callback results =-= + } + }); + } + return lib; +} \ No newline at end of file diff --git a/package.json b/package.json index 1a92b72..45a4415 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "dependencies": { "oauth": "0.9.x", "passport-strategy": "1.x.x", + "querystring": "^0.2.0", "request": "^2.75.0", "webfinger": "0.4.x" },