diff --git a/.jshintrc b/.jshintrc index c9f2f2d..bba5b74 100644 --- a/.jshintrc +++ b/.jshintrc @@ -10,6 +10,7 @@ "curly": true, "eqeqeq": true, "expr": true, + "node": true, "predef": [ "describe", diff --git a/README.md b/README.md index a79ea23..e58b286 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ Possible options values: * **refreshToken** _(Required)_ Refresh token for an user * **accessToken** _(Optional)_ initial access token. If not set, a new one will be generated * **timeout** _(Optional)_ TTL in **seconds** + * **customHeaders** _(Optional)_ custom headers to send during token generation request [yahoo requires `Authorization: Basic Base64(clientId:clientSecret)` ](https://developer.yahoo.com/oauth2/guide/flows_authcode/#step-5-exchange-refresh-token-for-new-access-token) + * **customParams** _(Optional)_ custom payload to send on getToken request [yahoo requires redirect_uri to be specified](https://developer.yahoo.com/oauth2/guide/flows_authcode/#step-5-exchange-refresh-token-for-new-access-token) See [https://developers.google.com/accounts/docs/OAuth2WebServer#offline]() for generating the required credentials @@ -58,7 +60,13 @@ If a new token value has been set, `'token'` event is emitted. user: "user@gmail.com", clientId: "{Client ID}", clientSecret: "{Client Secret}", - refreshToken: "{User Refresh Token}" + refreshToken: "{User Refresh Token}", + customHeaders: { + "HeaderName": "HeaderValue" + }, + customPayload: { + "payloadParamName": "payloadValue" + } }); // SMTP/IMAP diff --git a/package.json b/package.json index ab9b5d1..7153627 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "keywords": [ "XOAUTH", "XOAUTH2", + "Yahoo", "GMail", "SMTP", "IMAP" diff --git a/src/xoauth2.js b/src/xoauth2.js index f26588a..78b5a88 100644 --- a/src/xoauth2.js +++ b/src/xoauth2.js @@ -45,6 +45,8 @@ function XOAuth2Generator(options) { this.options = options || {}; this.options.accessUrl = this.options.accessUrl || 'https://accounts.google.com/o/oauth2/token'; + this.options.customHeaders = this.options.customHeaders || {}; + this.options.customParams = this.options.customParams || {}; this.token = this.options.accessToken && this.buildXOAuth2Token(this.options.accessToken) || false; this.accessToken = this.token && this.options.accessToken || false; @@ -98,10 +100,15 @@ XOAuth2Generator.prototype.generateToken = function(callback) { client_secret: this.options.clientSecret || '', refresh_token: this.options.refreshToken, grant_type: 'refresh_token' - }, - payload = querystring.stringify(urlOptions); + }; - postRequest(this.options.accessUrl, payload, (function(error, response, body) { + for (var param in this.options.customParams) { + urlOptions[param] = this.options.customParams[param]; + } + + var payload = querystring.stringify(urlOptions); + var self = this; + postRequest.call(this, this.options.accessUrl, payload, function (error, response, body) { var data; if (error) { @@ -123,12 +130,12 @@ XOAuth2Generator.prototype.generateToken = function(callback) { } if (data.access_token) { - this.updateToken(data.access_token, data.expires_in); - return callback(null, this.token, this.accessToken); + self.updateToken(data.access_token, data.expires_in); + return callback(null, self.token, self.accessToken); } return callback(new Error('No access token')); - }).bind(this)); + }); }; /** @@ -162,7 +169,8 @@ XOAuth2Generator.prototype.buildXOAuth2Token = function(accessToken) { function postRequest(url, payload, callback) { var options = urllib.parse(url), finished = false, - response = null; + response = null, + req; options.method = 'POST'; @@ -183,7 +191,7 @@ function postRequest(url, payload, callback) { callback.apply(null, arguments); }; - var req = (options.protocol === 'https:' ? https : http).request(options, function(res) { + req = (options.protocol === 'https:' ? https : http).request(options, function(res) { response = res; var data = []; var datalen = 0; @@ -211,5 +219,9 @@ function postRequest(url, payload, callback) { req.setHeader('Content-Length', typeof payload === 'string' ? Buffer.byteLength(payload) : payload.length); } + for (var customHeaderName in this.options.customHeaders) { + req.setHeader(customHeaderName, this.options.customHeaders[customHeaderName]); + } + req.end(payload); -} \ No newline at end of file +}