Source: oauth2.js

  1. /**
  2. * @file Manages Salesforce OAuth2 operations
  3. * @author Shinichi Tomita <shinichi.tomita@gmail.com>
  4. */
  5. 'use strict';
  6. var querystring = require('querystring'),
  7. _ = require('lodash/core'),
  8. Transport = require('./transport');
  9. var defaults = {
  10. loginUrl : "https://login.salesforce.com"
  11. };
  12. /**
  13. * OAuth2 class
  14. *
  15. * @class
  16. * @constructor
  17. * @param {Object} options - OAuth2 config options
  18. * @param {String} [options.loginUrl] - Salesforce login server URL
  19. * @param {String} [options.authzServiceUrl] - OAuth2 authorization service URL. If not specified, it generates from default by adding to login server URL.
  20. * @param {String} [options.tokenServiceUrl] - OAuth2 token service URL. If not specified it generates from default by adding to login server URL.
  21. * @param {String} options.clientId - OAuth2 client ID.
  22. * @param {String} options.clientSecret - OAuth2 client secret.
  23. * @param {String} options.redirectUri - URI to be callbacked from Salesforce OAuth2 authorization service.
  24. */
  25. var OAuth2 = module.exports = function(options) {
  26. if (options.authzServiceUrl && options.tokenServiceUrl) {
  27. this.loginUrl = options.authzServiceUrl.split('/').slice(0, 3).join('/');
  28. this.authzServiceUrl = options.authzServiceUrl;
  29. this.tokenServiceUrl = options.tokenServiceUrl;
  30. this.revokeServiceUrl = options.revokeServiceUrl;
  31. } else {
  32. this.loginUrl = options.loginUrl || defaults.loginUrl;
  33. this.authzServiceUrl = this.loginUrl + "/services/oauth2/authorize";
  34. this.tokenServiceUrl = this.loginUrl + "/services/oauth2/token";
  35. this.revokeServiceUrl = this.loginUrl + "/services/oauth2/revoke";
  36. }
  37. this.clientId = options.clientId;
  38. this.clientSecret = options.clientSecret;
  39. this.redirectUri = options.redirectUri;
  40. this._transport =
  41. options.proxyUrl ? new Transport.ProxyTransport(options.proxyUrl) : new Transport();
  42. };
  43. /**
  44. *
  45. */
  46. _.extend(OAuth2.prototype, /** @lends OAuth2.prototype **/ {
  47. /**
  48. * Get Salesforce OAuth2 authorization page URL to redirect user agent.
  49. *
  50. * @param {Object} params - Parameters
  51. * @param {String} params.scope - Scope values in space-separated string
  52. * @param {String} params.state - State parameter
  53. * @returns {String} Authorization page URL
  54. */
  55. getAuthorizationUrl : function(params) {
  56. params = _.extend({
  57. response_type : "code",
  58. client_id : this.clientId,
  59. redirect_uri : this.redirectUri
  60. }, params || {});
  61. return this.authzServiceUrl +
  62. (this.authzServiceUrl.indexOf('?') >= 0 ? "&" : "?") +
  63. querystring.stringify(params);
  64. },
  65. /**
  66. * @typedef TokenResponse
  67. * @type {Object}
  68. * @property {String} access_token
  69. * @property {String} refresh_token
  70. */
  71. /**
  72. * OAuth2 Refresh Token Flow
  73. *
  74. * @param {String} refreshToken - Refresh token
  75. * @param {Callback.<TokenResponse>} [callback] - Callback function
  76. * @returns {Promise.<TokenResponse>}
  77. */
  78. refreshToken : function(refreshToken, callback) {
  79. return this._postParams({
  80. grant_type : "refresh_token",
  81. refresh_token : refreshToken,
  82. client_id : this.clientId,
  83. client_secret : this.clientSecret
  84. }, callback);
  85. },
  86. /**
  87. * OAuth2 Web Server Authentication Flow (Authorization Code)
  88. * Access Token Request
  89. *
  90. * @param {String} code - Authorization code
  91. * @param {Callback.<TokenResponse>} [callback] - Callback function
  92. * @returns {Promise.<TokenResponse>}
  93. */
  94. requestToken : function(code, callback) {
  95. return this._postParams({
  96. grant_type : "authorization_code",
  97. code : code,
  98. client_id : this.clientId,
  99. client_secret : this.clientSecret,
  100. redirect_uri : this.redirectUri
  101. }, callback);
  102. },
  103. /**
  104. * OAuth2 Username-Password Flow (Resource Owner Password Credentials)
  105. *
  106. * @param {String} username - Salesforce username
  107. * @param {String} password - Salesforce password
  108. * @param {Callback.<TokenResponse>} [callback] - Callback function
  109. * @returns {Promise.<TokenResponse>}
  110. */
  111. authenticate : function(username, password, callback) {
  112. return this._postParams({
  113. grant_type : "password",
  114. username : username,
  115. password : password,
  116. client_id : this.clientId,
  117. client_secret : this.clientSecret,
  118. redirect_uri : this.redirectUri
  119. }, callback);
  120. },
  121. /**
  122. * OAuth2 Revoke Session Token
  123. *
  124. * @param {String} accessToken - Access token to revoke
  125. * @param {Callback.<undefined>} [callback] - Callback function
  126. * @returns {Promise.<undefined>}
  127. */
  128. revokeToken : function(accessToken, callback) {
  129. return this._transport.httpRequest({
  130. method : 'POST',
  131. url : this.revokeServiceUrl,
  132. body: querystring.stringify({ token: accessToken }),
  133. headers: {
  134. "content-type" : "application/x-www-form-urlencoded"
  135. }
  136. }).then(function(response) {
  137. if (response.statusCode >= 400) {
  138. var res = querystring.parse(response.body);
  139. if (!res || !res.error) {
  140. res = { error: "ERROR_HTTP_"+response.statusCode, error_description: response.body };
  141. }
  142. var err = new Error(res.error_description);
  143. err.name = res.error;
  144. throw err;
  145. }
  146. }).thenCall(callback);
  147. },
  148. /**
  149. * @private
  150. */
  151. _postParams : function(params, callback) {
  152. return this._transport.httpRequest({
  153. method : 'POST',
  154. url : this.tokenServiceUrl,
  155. body : querystring.stringify(params),
  156. headers : {
  157. "content-type" : "application/x-www-form-urlencoded"
  158. }
  159. }).then(function(response) {
  160. var res;
  161. try {
  162. res = JSON.parse(response.body);
  163. } catch(e) {}
  164. if (response.statusCode >= 400) {
  165. res = res || { error: "ERROR_HTTP_"+response.statusCode, error_description: response.body };
  166. var err = new Error(res.error_description);
  167. err.name = res.error;
  168. throw err;
  169. }
  170. return res;
  171. }).thenCall(callback);
  172. }
  173. });