jsforce2
Version:
Salesforce API Library for JavaScript
207 lines (191 loc) • 6.8 kB
JavaScript
/**
* @file Manages Salesforce OAuth2 operations
* @author Shinichi Tomita <shinichi.tomita@gmail.com>
*/
'use strict';
var querystring = require('querystring'),
_ = require('lodash/core'),
Transport = require('./transport');
var defaults = {
loginUrl : "https://login.salesforce.com"
};
/**
* OAuth2 class
*
* @class
* @constructor
* @param {Object} options - OAuth2 config options
* @param {String} [options.loginUrl] - Salesforce login server URL
* @param {String} [options.authzServiceUrl] - OAuth2 authorization service URL. If not specified, it generates from default by adding to login server URL.
* @param {String} [options.tokenServiceUrl] - OAuth2 token service URL. If not specified it generates from default by adding to login server URL.
* @param {String} options.clientId - OAuth2 client ID.
* @param {String} [options.clientSecret] - OAuth2 client secret (This is optional for public client).
* @param {String} options.redirectUri - URI to be callbacked from Salesforce OAuth2 authorization service.
*/
var OAuth2 = module.exports = function(options) {
if (options.authzServiceUrl && options.tokenServiceUrl) {
this.loginUrl = options.authzServiceUrl.split('/').slice(0, 3).join('/');
this.authzServiceUrl = options.authzServiceUrl;
this.tokenServiceUrl = options.tokenServiceUrl;
this.revokeServiceUrl = options.revokeServiceUrl;
} else {
this.loginUrl = options.loginUrl || defaults.loginUrl;
this.authzServiceUrl = this.loginUrl + "/services/oauth2/authorize";
this.tokenServiceUrl = this.loginUrl + "/services/oauth2/token";
this.revokeServiceUrl = this.loginUrl + "/services/oauth2/revoke";
}
this.clientId = options.clientId;
this.clientSecret = options.clientSecret;
this.redirectUri = options.redirectUri;
if (options.proxyUrl) {
this._transport = new Transport.ProxyTransport(options.proxyUrl);
} else if (options.httpProxy) {
this._transport = new Transport.HttpProxyTransport(options.httpProxy);
} else {
this._transport = new Transport();
}
};
/**
*
*/
_.extend(OAuth2.prototype, /** @lends OAuth2.prototype **/ {
/**
* Get Salesforce OAuth2 authorization page URL to redirect user agent.
*
* @param {Object} params - Parameters
* @param {String} [params.scope] - Scope values in space-separated string
* @param {String} [params.state] - State parameter
* @param {String} [params.code_challenge] - Code challenge value (RFC 7636 - Proof Key of Code Exchange)
* @returns {String} Authorization page URL
*/
getAuthorizationUrl : function(params) {
params = _.extend({
response_type : "code",
client_id : this.clientId,
redirect_uri : this.redirectUri
}, params || {});
return this.authzServiceUrl +
(this.authzServiceUrl.indexOf('?') >= 0 ? "&" : "?") +
querystring.stringify(params);
},
/**
* @typedef TokenResponse
* @type {Object}
* @property {String} access_token
* @property {String} refresh_token
*/
/**
* OAuth2 Refresh Token Flow
*
* @param {String} refreshToken - Refresh token
* @param {Callback.<TokenResponse>} [callback] - Callback function
* @returns {Promise.<TokenResponse>}
*/
refreshToken : function(refreshToken, callback) {
var params = {
grant_type : "refresh_token",
refresh_token : refreshToken,
client_id : this.clientId
};
if (this.clientSecret) {
params.client_secret = this.clientSecret;
}
return this._postParams(params, callback);
},
/**
* OAuth2 Web Server Authentication Flow (Authorization Code)
* Access Token Request
*
* @param {String} code - Authorization code
* @param {Object} [params] - Optional parameters to send in token retrieval
* @param {String} [params.code_verifier] - Code verifier value (RFC 7636 - Proof Key of Code Exchange)
* @param {Callback.<TokenResponse>} [callback] - Callback function
* @returns {Promise.<TokenResponse>}
*/
requestToken : function(code, params, callback) {
if (typeof params === 'function') {
callback = params;
params = {};
}
params = _.extend({
grant_type : "authorization_code",
code : code,
client_id : this.clientId,
redirect_uri : this.redirectUri
}, params || {});
if (this.clientSecret) {
params.client_secret = this.clientSecret;
}
return this._postParams(params, callback);
},
/**
* OAuth2 Username-Password Flow (Resource Owner Password Credentials)
*
* @param {String} username - Salesforce username
* @param {String} password - Salesforce password
* @param {Callback.<TokenResponse>} [callback] - Callback function
* @returns {Promise.<TokenResponse>}
*/
authenticate : function(username, password, callback) {
return this._postParams({
grant_type : "password",
username : username,
password : password,
client_id : this.clientId,
client_secret : this.clientSecret,
redirect_uri : this.redirectUri
}, callback);
},
/**
* OAuth2 Revoke Session or API Token
*
* @param {String} token - Access or Refresh token to revoke. Passing in the Access token revokes the session. Passing in the Refresh token revokes API Access.
* @param {Callback.<undefined>} [callback] - Callback function
* @returns {Promise.<undefined>}
*/
revokeToken : function(token, callback) {
return this._transport.httpRequest({
method : 'POST',
url : this.revokeServiceUrl,
body: querystring.stringify({ token: token }),
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
}).then(function(response) {
if (response.statusCode >= 400) {
var res = querystring.parse(response.body);
if (!res || !res.error) {
res = { error: "ERROR_HTTP_"+response.statusCode, error_description: response.body };
}
var err = new Error(res.error_description);
err.name = res.error;
throw err;
}
}).thenCall(callback);
},
/**
* @private
*/
_postParams : function(params, callback) {
return this._transport.httpRequest({
method : 'POST',
url : this.tokenServiceUrl,
body : querystring.stringify(params),
headers : {
"content-type" : "application/x-www-form-urlencoded"
}
}).then(function(response) {
var res;
try {
res = JSON.parse(response.body);
} catch(e) {}
if (response.statusCode >= 400) {
res = res || { error: "ERROR_HTTP_"+response.statusCode, error_description: response.body };
var err = new Error(res.error_description);
err.name = res.error;
throw err;
}
return res;
}).thenCall(callback);
}
});