///
import { ConfigurationError } from './error';
import { WebApiClient } from '../web-api/web-api-client';
import { WebApiConfiguration } from './web-api-configuration';
/**
* @export
* @class AccessTokenProvider
* @implements {AccessTokenProviderInterface}
*/
export class AccessTokenProvider implements AccessTokenProviderInterface {
private token: AccessToken;
private client: WebApiClient;
private code: string;
private secret: string;
/**
* Set access token given in initialization
* @param {WebApiConfiguration} config
*/
constructor(config: WebApiConfiguration) {
this.client = new AccessTokenProviderClient(config);
if (config.oauth2 && config.oauth2.clientSecret) {
this.secret = config.oauth2.clientSecret;
}
}
/**
* Set token and expiration properties of a given tokeng
* @param {AccessToken|string} token
* @returns {void}
*/
useAccessToken(token: AccessToken | string): void {
if (typeof token === 'string') {
this.token = {
token: token,
tokenType: 'bearer',
expiresIn: Date.now()
}
return;
}
this.token = token;
this.token.expiresIn = Date.now() + ((token).expiresIn * 1000) - 5000;
}
/**
* @param {string} code
*/
useCode(code: string) {
this.code = code;
}
/**
* @returns {string}
*/
getCode(): string {
return this.code;
}
/**
* @returns {Promise}
*/
getAccessToken(): Promise {
return new Promise((resolve, reject) => {
// Resolve with saved access token if it's not expired else call refreshAccessToken method
if (this.token && (Date.now() < this.token.expiresIn) || !this.secret) {
resolve(this.token);
} else if (this.token) {
this.refreshAccessToken();
} else {
if (!this.code) {
throw new ConfigurationError('Code has to be set before getting access token. Use ProcessRedirect function for parsing redirect url with code or useCode function to set the code');
}
var data = {
grant_type: 'authorization_code',
code: this.code,
client_id: this.client.config.oauth2.clientId,
client_secret: this.client.config.oauth2.clientSecret,
redirect_uri: this.client.config.oauth2.redirectUri,
expires_in: '3600',
}
this.client.callApi(`${this.client.config.environment.oAuth2ContextBaseUrl}/token`, 'POST', null, this.joinAndEncodeData(data), { 'Content-Type': 'application/x-www-form-urlencoded', 'web-api-key': '', })
.then(token => {
this.useAccessToken({
token: token.access_token,
tokenType: token.token_type,
expiresIn: token.expires_in
});
resolve(this.token);
});
}
});
}
/**
* Refresh access token and return it in promise
* @returns {Promise}
*/
refreshAccessToken(): Promise {
if (!this.secret) {
throw new ConfigurationError('Access token cannot be refreshed if you use implicit flow');
}
// Throw ConfigurationError if client is not set
if (!this.client) {
throw new ConfigurationError('WebApiClient has to be set on AccessTokenProvider if you want use it');
}
if (!this.client.config.oauth2.clientId || !this.client.config.oauth2.redirectUri) {
throw new ConfigurationError('clientId and redirectUri has to be set if you want to get access token');
}
return new Promise((resolve, reject) => {
var data = {
refresh_token: this.token.refreshToken,
code: this.code,
client_id: this.client.config.oauth2.clientId,
client_secret: this.client.config.oauth2.clientSecret,
redirect_uri: this.client.config.oauth2.redirectUri,
grant_type: 'refresh_token'
}
// Call client's makeCall method to perform call on the API server
this.client.callApi(
`${this.client.config.environment.oAuth2ContextBaseUrl}/token`,
'POST',
null,
this.joinAndEncodeData(data),
{ "Content-Type": "application/x-www-form-urlencoded" }
).then(token => {
// If call is successful then set token and resolve
this.useAccessToken({
token: token.access_token,
tokenType: token.token_type,
expiresIn: token.expires_in
});
resolve(this.token);
})
.catch(error => {
// reject with error if call is unsuccessful
reject(error);
});
});
}
/**
* Helper method to join and encode data
* @private
* @param {any} data
* @returns {string}
*/
private joinAndEncodeData(data: any): string {
var arr = [];
for (var prop in data) {
arr.push(`${prop}=${data[prop]}`);
}
return encodeURI(arr.join('&'));
}
}
/**
* @export
* @interface AccessTokenProviderInterface
*/
export interface AccessTokenProviderInterface {
/**
* Returns access token
*/
getAccessToken(): Promise;
/**
* Calls the API in order to refresh token and returns
*/
refreshAccessToken(): Promise;
/**
* Sets access token on
*/
useAccessToken(token: AccessToken | string): void;
useCode(string): void;
getCode(): string;
}
/**
* @export
* @interface AccessToken
*/
export interface AccessToken {
token: string;
expiresIn: number;
tokenType: string;
refreshToken?: string;
}
/**
* @export
* @class AccessTokenProviderClient
* @extends {WebApiClient}
*/
export class AccessTokenProviderClient extends WebApiClient {
constructor(config) {
super(config, '');
}
}