@factset/sdk-utils
Version:
Utilities for interacting with FactSet APIs.
101 lines (100 loc) • 4.86 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfidentialClient = void 0;
const _1 = require(".");
const openIDClientFactory_1 = require("./openIDClientFactory");
const configuration_1 = require("./configuration");
const constants_1 = require("./constants");
const unixTimestamp_1 = require("./unixTimestamp");
const debug_1 = __importDefault(require("debug"));
const https_proxy_agent_1 = require("https-proxy-agent");
const debug = (0, debug_1.default)(`${constants_1.PACKAGE_NAME}:ConfidentialClient`);
/**
* Helper class that supports FactSet's implementation of the OAuth 2.0
* client credentials flow.
*
* The main purpose of this class is to provide an access token that can
* be used to authenticate against FactSet's APIs. It takes care of fetching
* the access token, caching it and refreshing it as needed.
*/
class ConfidentialClient {
constructor(param, _options) {
this._config = configuration_1.Configuration.loadConfig(param);
this._token = new _1.Token('', 0);
this._options = _options !== null && _options !== void 0 ? _options : null;
}
/**
* Returns an access token that can be used for authentication.
*
* If the cache contains a valid access token, it's returned. Otherwise
* a new access token is retrieved from FactSet's authorization server.
*
* The access token should be used immediately and not stored to avoid
* any issues with token expiry.
*
* The access token is used in the Authorization header when when accessing
* FactSet's APIs. Example: `{"Authorization": "Bearer access-token"}`
*
* @returns access token for protected resource requests
*/
getAccessToken() {
var _a;
return __awaiter(this, void 0, void 0, function* () {
if (this._token.isExpired() === false) {
debug('Retrieving cached token. Expires at %d, in %d seconds.', this._token.expiresAt, this._token.expiresIn);
return this._token.token;
}
debug('Token is expired or invalid');
if ((_a = this._options) === null || _a === void 0 ? void 0 : _a.proxyUrl) {
const proxyAgent = new https_proxy_agent_1.HttpsProxyAgent(`${this._options.proxyUrl}`);
this._openIDClient = yield openIDClientFactory_1.OpenIDClientFactory.getClient(this._config, proxyAgent);
}
else {
this._openIDClient = yield openIDClientFactory_1.OpenIDClientFactory.getClient(this._config);
}
this._token = yield this.fetchAccessToken();
return this._token.token;
});
}
fetchAccessToken() {
return __awaiter(this, void 0, void 0, function* () {
debug('Fetching new access token');
try {
const now = (0, unixTimestamp_1.unixTimestamp)();
const tokenSet = yield this._openIDClient.grant({
grant_type: 'client_credentials',
}, {
clientAssertionPayload: {
nbf: now - constants_1.JWT_NOT_BEFORE_SECS,
iat: now,
exp: now + constants_1.JWT_EXPIRE_AFTER_SECS,
},
});
if (tokenSet.access_token === undefined || tokenSet.expires_at === undefined) {
throw new _1.AccessTokenError('Got an invalid token');
}
debug('Got access token that expires at %d, in %d seconds', tokenSet.expires_at, tokenSet.expires_in);
return new _1.Token(tokenSet.access_token, tokenSet.expires_at);
}
catch (error) {
if (error instanceof _1.AccessTokenError) {
throw error;
}
throw new _1.AccessTokenError('Error attempting to get access token', error);
}
});
}
}
exports.ConfidentialClient = ConfidentialClient;