From ebe9c2ffebbf1c385e295fb21e5ce4e311367965 Mon Sep 17 00:00:00 2001 From: Saad Jutt Date: Thu, 9 Dec 2021 11:43:50 +0500 Subject: [PATCH] feat: get access token & refresh tokens for server type SASJS --- src/SASViyaApiClient.ts | 15 ++- src/SASjs.ts | 100 +++++++++++------- src/SASjsApiClient.ts | 28 +++++ src/auth/getAccessTokenForSasjs.ts | 36 +++++++ ...ccessToken.ts => getAccessTokenForViya.ts} | 2 +- src/auth/getTokens.ts | 25 +++-- src/auth/refreshTokensForSasjs.ts | 35 ++++++ ...freshTokens.ts => refreshTokensForViya.ts} | 4 +- src/auth/spec/getAccessTokenForSasjs.spec.ts | 65 ++++++++++++ ....spec.ts => getAccessTokenForViya.spec.ts} | 8 +- src/auth/spec/getTokens.spec.ts | 10 +- src/auth/spec/mockResponses.ts | 5 + src/auth/spec/refreshTokensForSasjs.spec.ts | 47 ++++++++ ...s.spec.ts => refreshTokensForViya.spec.ts} | 8 +- 14 files changed, 319 insertions(+), 69 deletions(-) create mode 100644 src/auth/getAccessTokenForSasjs.ts rename src/auth/{getAccessToken.ts => getAccessTokenForViya.ts} (97%) create mode 100644 src/auth/refreshTokensForSasjs.ts rename src/auth/{refreshTokens.ts => refreshTokensForViya.ts} (92%) create mode 100644 src/auth/spec/getAccessTokenForSasjs.spec.ts rename src/auth/spec/{getAccessToken.spec.ts => getAccessTokenForViya.spec.ts} (91%) create mode 100644 src/auth/spec/refreshTokensForSasjs.spec.ts rename src/auth/spec/{refreshTokens.spec.ts => refreshTokensForViya.spec.ts} (91%) diff --git a/src/SASViyaApiClient.ts b/src/SASViyaApiClient.ts index 4cd6abe..53557e5 100644 --- a/src/SASViyaApiClient.ts +++ b/src/SASViyaApiClient.ts @@ -22,8 +22,8 @@ import { pollJobState } from './api/viya/pollJobState' import { getTokens } from './auth/getTokens' import { uploadTables } from './api/viya/uploadTables' import { executeScript } from './api/viya/executeScript' -import { getAccessToken } from './auth/getAccessToken' -import { refreshTokens } from './auth/refreshTokens' +import { getAccessTokenForViya } from './auth/getAccessTokenForViya' +import { refreshTokensForViya } from './auth/refreshTokensForViya' /** * A client for interfacing with the SAS Viya REST API. @@ -534,21 +534,26 @@ export class SASViyaApiClient { clientSecret: string, authCode: string ): Promise { - return getAccessToken(this.requestClient, clientId, clientSecret, authCode) + return getAccessTokenForViya( + this.requestClient, + clientId, + clientSecret, + authCode + ) } /** * Exchanges the refresh token for an access token for the given client. * @param clientId - the client ID to authenticate with. * @param clientSecret - the client secret to authenticate with. - * @param authCode - the refresh token received from the server. + * @param refreshToken - the refresh token received from the server. */ public async refreshTokens( clientId: string, clientSecret: string, refreshToken: string ) { - return refreshTokens( + return refreshTokensForViya( this.requestClient, clientId, clientSecret, diff --git a/src/SASjs.ts b/src/SASjs.ts index 1b1359e..0027f5f 100644 --- a/src/SASjs.ts +++ b/src/SASjs.ts @@ -11,13 +11,14 @@ import { } from './types' import { SASViyaApiClient } from './SASViyaApiClient' import { SAS9ApiClient } from './SAS9ApiClient' -import { SASjsApiClient } from './SASjsApiClient' +import { SASjsApiClient, SASjsAuthResponse } from './SASjsApiClient' import { AuthManager } from './auth' import { ServerType, MacroVar, AuthConfig, - ExtraResponseAttributes + ExtraResponseAttributes, + SasAuthResponse } from '@sasjs/utils/types' import { RequestClient } from './request/RequestClient' import { @@ -53,7 +54,7 @@ export default class SASjs { private jobsPath: string = '' private sasViyaApiClient: SASViyaApiClient | null = null private sas9ApiClient: SAS9ApiClient | null = null - private SASjsApiClient: SASjsApiClient | null = null + private sasJSApiClient: SASjsApiClient | null = null private fileUploader: FileUploader | null = null private authManager: AuthManager | null = null private requestClient: RequestClient | null = null @@ -80,7 +81,7 @@ export default class SASjs { userName: string, password: string ) { - this.isMethodSupported('executeScriptSAS9', ServerType.Sas9) + this.isMethodSupported('executeScriptSAS9', [ServerType.Sas9]) return await this.sas9ApiClient?.executeScript( linesOfCode, @@ -94,7 +95,7 @@ export default class SASjs { * @param accessToken - an access token for an authorized user. */ public async getComputeContexts(accessToken: string) { - this.isMethodSupported('getComputeContexts', ServerType.SasViya) + this.isMethodSupported('getComputeContexts', [ServerType.SasViya]) return await this.sasViyaApiClient!.getComputeContexts(accessToken) } @@ -104,7 +105,7 @@ export default class SASjs { * @param accessToken - an access token for an authorized user. */ public async getLauncherContexts(accessToken: string) { - this.isMethodSupported('getLauncherContexts', ServerType.SasViya) + this.isMethodSupported('getLauncherContexts', [ServerType.SasViya]) return await this.sasViyaApiClient!.getLauncherContexts(accessToken) } @@ -113,7 +114,7 @@ export default class SASjs { * Gets default(system) launcher contexts. */ public getDefaultComputeContexts() { - this.isMethodSupported('getDefaultComputeContexts', ServerType.SasViya) + this.isMethodSupported('getDefaultComputeContexts', [ServerType.SasViya]) return this.sasViyaApiClient!.getDefaultComputeContexts() } @@ -123,7 +124,7 @@ export default class SASjs { * @param authConfig - an access token, refresh token, client and secret for an authorized user. */ public async getExecutableContexts(authConfig: AuthConfig) { - this.isMethodSupported('getExecutableContexts', ServerType.SasViya) + this.isMethodSupported('getExecutableContexts', [ServerType.SasViya]) return await this.sasViyaApiClient!.getExecutableContexts(authConfig) } @@ -145,7 +146,7 @@ export default class SASjs { accessToken: string, authorizedUsers?: string[] ) { - this.isMethodSupported('createComputeContext', ServerType.SasViya) + this.isMethodSupported('createComputeContext', [ServerType.SasViya]) return await this.sasViyaApiClient!.createComputeContext( contextName, @@ -170,7 +171,7 @@ export default class SASjs { launchType: string, accessToken: string ) { - this.isMethodSupported('createLauncherContext', ServerType.SasViya) + this.isMethodSupported('createLauncherContext', [ServerType.SasViya]) return await this.sasViyaApiClient!.createLauncherContext( contextName, @@ -191,7 +192,7 @@ export default class SASjs { editedContext: EditContextInput, accessToken?: string ) { - this.isMethodSupported('editComputeContext', ServerType.SasViya) + this.isMethodSupported('editComputeContext', [ServerType.SasViya]) return await this.sasViyaApiClient!.editComputeContext( contextName, @@ -206,7 +207,7 @@ export default class SASjs { * @param accessToken - an access token for an authorized user. */ public async deleteComputeContext(contextName: string, accessToken?: string) { - this.isMethodSupported('deleteComputeContext', ServerType.SasViya) + this.isMethodSupported('deleteComputeContext', [ServerType.SasViya]) return await this.sasViyaApiClient!.deleteComputeContext( contextName, @@ -224,7 +225,7 @@ export default class SASjs { contextName: string, accessToken?: string ) { - this.isMethodSupported('getComputeContextByName', ServerType.SasViya) + this.isMethodSupported('getComputeContextByName', [ServerType.SasViya]) return await this.sasViyaApiClient!.getComputeContextByName( contextName, @@ -238,7 +239,7 @@ export default class SASjs { * @param accessToken - an access token for an authorized user. */ public async getComputeContextById(contextId: string, accessToken?: string) { - this.isMethodSupported('getComputeContextById', ServerType.SasViya) + this.isMethodSupported('getComputeContextById', [ServerType.SasViya]) return await this.sasViyaApiClient!.getComputeContextById( contextId, @@ -247,7 +248,7 @@ export default class SASjs { } public async createSession(contextName: string, accessToken: string) { - this.isMethodSupported('createSession', ServerType.SasViya) + this.isMethodSupported('createSession', [ServerType.SasViya]) return await this.sasViyaApiClient!.createSession(contextName, accessToken) } @@ -267,7 +268,7 @@ export default class SASjs { authConfig?: AuthConfig, debug?: boolean ) { - this.isMethodSupported('executeScriptSASViya', ServerType.SasViya) + this.isMethodSupported('executeScriptSASViya', [ServerType.SasViya]) if (!contextName) { throw new Error( 'Context name is undefined. Please set a `contextName` in your SASjs or override config.' @@ -357,7 +358,7 @@ export default class SASjs { * @param accessToken - the access token to authorize the request. */ public async getFolder(folderPath: string, accessToken?: string) { - this.isMethodSupported('getFolder', ServerType.SasViya) + this.isMethodSupported('getFolder', [ServerType.SasViya]) return await this.sasViyaApiClient!.getFolder(folderPath, accessToken) } @@ -367,7 +368,7 @@ export default class SASjs { * @param accessToken - an access token for authorizing the request. */ public async deleteFolder(folderPath: string, accessToken: string) { - this.isMethodSupported('deleteFolder', ServerType.SasViya) + this.isMethodSupported('deleteFolder', [ServerType.SasViya]) return await this.sasViyaApiClient?.deleteFolder(folderPath, accessToken) } @@ -382,7 +383,7 @@ export default class SASjs { accessToken?: string, limit?: number ) { - this.isMethodSupported('listFolder', ServerType.SasViya) + this.isMethodSupported('listFolder', [ServerType.SasViya]) return await this.sasViyaApiClient?.listFolder( sourceFolder, @@ -404,7 +405,7 @@ export default class SASjs { targetFolderName: string, accessToken: string ) { - this.isMethodSupported('moveFolder', ServerType.SasViya) + this.isMethodSupported('moveFolder', [ServerType.SasViya]) return await this.sasViyaApiClient?.moveFolder( sourceFolder, @@ -422,7 +423,7 @@ export default class SASjs { accessToken?: string, sasApiClient?: SASViyaApiClient ) { - this.isMethodSupported('createJobDefinition', ServerType.SasViya) + this.isMethodSupported('createJobDefinition', [ServerType.SasViya]) if (sasApiClient) return await sasApiClient!.createJobDefinition( @@ -442,7 +443,7 @@ export default class SASjs { } public async getAuthCode(clientId: string) { - this.isMethodSupported('getAuthCode', ServerType.SasViya) + this.isMethodSupported('getAuthCode', [ServerType.SasViya]) return await this.sasViyaApiClient!.getAuthCode(clientId) } @@ -457,8 +458,14 @@ export default class SASjs { clientId: string, clientSecret: string, authCode: string - ) { - this.isMethodSupported('getAccessToken', ServerType.SasViya) + ): Promise { + this.isMethodSupported('getAccessToken', [ + ServerType.SasViya, + ServerType.Sasjs + ]) + + if (this.sasjsConfig.serverType === ServerType.Sasjs) + return await this.sasJSApiClient!.getAccessToken(clientId, authCode) return await this.sasViyaApiClient!.getAccessToken( clientId, @@ -467,12 +474,24 @@ export default class SASjs { ) } + /** + * Exchanges the refresh token for an access token for the given client. + * @param clientId - the client ID to authenticate with. + * @param clientSecret - the client secret to authenticate with. + * @param refreshToken - the refresh token received from the server. + */ public async refreshTokens( clientId: string, clientSecret: string, refreshToken: string - ) { - this.isMethodSupported('refreshTokens', ServerType.SasViya) + ): Promise { + this.isMethodSupported('refreshTokens', [ + ServerType.SasViya, + ServerType.Sasjs + ]) + + if (this.sasjsConfig.serverType === ServerType.Sasjs) + return await this.sasJSApiClient!.refreshTokens(refreshToken) return await this.sasViyaApiClient!.refreshTokens( clientId, @@ -482,7 +501,7 @@ export default class SASjs { } public async deleteClient(clientId: string, accessToken: string) { - this.isMethodSupported('deleteClient', ServerType.SasViya) + this.isMethodSupported('deleteClient', [ServerType.SasViya]) return await this.sasViyaApiClient!.deleteClient(clientId, accessToken) } @@ -777,7 +796,7 @@ export default class SASjs { accessToken?: string, isForced = false ) { - this.isMethodSupported('deployServicePack', ServerType.SasViya) + this.isMethodSupported('deployServicePack', [ServerType.SasViya]) let sasApiClient: any = null if (serverUrl || appLoc) { @@ -832,11 +851,11 @@ export default class SASjs { } public async deployToSASjs(members: [FolderMember, ServiceMember]) { - return await this.SASjsApiClient?.deploy(members, this.sasjsConfig.appLoc) + return await this.sasJSApiClient?.deploy(members, this.sasjsConfig.appLoc) } public async executeJobSASjs(query: ExecutionQuery) { - return await this.SASjsApiClient?.executeJob(query) + return await this.sasJSApiClient?.executeJob(query) } /** @@ -872,7 +891,7 @@ export default class SASjs { ...config } - this.isMethodSupported('startComputeJob', ServerType.SasViya) + this.isMethodSupported('startComputeJob', [ServerType.SasViya]) if (!config.contextName) { throw new Error( 'Context name is undefined. Please set a `contextName` in your SASjs or override config.' @@ -1020,10 +1039,10 @@ export default class SASjs { } if (this.sasjsConfig.serverType === ServerType.Sasjs) { - if (this.SASjsApiClient) { - this.SASjsApiClient.setConfig(this.sasjsConfig.serverUrl) + if (this.sasJSApiClient) { + this.sasJSApiClient.setConfig(this.sasjsConfig.serverUrl) } else { - this.SASjsApiClient = new SASjsApiClient( + this.sasJSApiClient = new SASjsApiClient( this.sasjsConfig.serverUrl, this.requestClient ) @@ -1117,12 +1136,15 @@ export default class SASjs { }) } - private isMethodSupported(method: string, serverType: string) { - if (this.sasjsConfig.serverType !== serverType) { + private isMethodSupported(method: string, serverTypes: ServerType[]) { + if ( + !this.sasjsConfig.serverType || + !serverTypes.includes(this.sasjsConfig.serverType) + ) { throw new Error( - `Method '${method}' is only supported on ${ - serverType === ServerType.Sas9 ? 'SAS9' : 'SAS Viya' - } servers.` + `Method '${method}' is only supported on ${serverTypes.join( + ', ' + )} servers.` ) } } diff --git a/src/SASjsApiClient.ts b/src/SASjsApiClient.ts index 7ae4208..62980c8 100644 --- a/src/SASjsApiClient.ts +++ b/src/SASjsApiClient.ts @@ -1,5 +1,7 @@ import { FolderMember, ServiceMember, ExecutionQuery } from './types' import { RequestClient } from './request/RequestClient' +import { getAccessTokenForSasjs } from './auth/getAccessTokenForSasjs' +import { refreshTokensForSasjs } from './auth/refreshTokensForSasjs' export class SASjsApiClient { constructor( @@ -36,4 +38,30 @@ export class SASjsApiClient { return Promise.resolve(result) } + + /** + * Exchanges the auth code for an access token for the given client. + * @param clientId - the client ID to authenticate with. + * @param authCode - the auth code received from the server. + */ + public async getAccessToken( + clientId: string, + authCode: string + ): Promise { + return getAccessTokenForSasjs(this.requestClient, clientId, authCode) + } + + /** + * Exchanges the refresh token for an access token. + * @param refreshToken - the refresh token received from the server. + */ + public async refreshTokens(refreshToken: string): Promise { + return refreshTokensForSasjs(this.requestClient, refreshToken) + } +} + +// todo move to sasjs/utils +export interface SASjsAuthResponse { + access_token: string + refresh_token: string } diff --git a/src/auth/getAccessTokenForSasjs.ts b/src/auth/getAccessTokenForSasjs.ts new file mode 100644 index 0000000..7b080bf --- /dev/null +++ b/src/auth/getAccessTokenForSasjs.ts @@ -0,0 +1,36 @@ +import { prefixMessage } from '@sasjs/utils/error' +import { RequestClient } from '../request/RequestClient' + +/** + * Exchanges the auth code for an access token for the given client. + * @param requestClient - the pre-configured HTTP request client + * @param clientId - the client ID to authenticate with. + * @param authCode - the auth code received from the server. + */ +export async function getAccessTokenForSasjs( + requestClient: RequestClient, + clientId: string, + authCode: string +) { + const url = '/SASjsApi/auth/token' + const data = { + clientId, + code: authCode + } + + return await requestClient + .post(url, data, undefined) + .then((res) => { + const sasAuth = res.result as { + accessToken: string + refreshToken: string + } + return { + access_token: sasAuth.accessToken, + refresh_token: sasAuth.refreshToken + } + }) + .catch((err) => { + throw prefixMessage(err, 'Error while getting access token. ') + }) +} diff --git a/src/auth/getAccessToken.ts b/src/auth/getAccessTokenForViya.ts similarity index 97% rename from src/auth/getAccessToken.ts rename to src/auth/getAccessTokenForViya.ts index f42e442..d4f97a8 100644 --- a/src/auth/getAccessToken.ts +++ b/src/auth/getAccessTokenForViya.ts @@ -10,7 +10,7 @@ import { RequestClient } from '../request/RequestClient' * @param clientSecret - the client secret to authenticate with. * @param authCode - the auth code received from the server. */ -export async function getAccessToken( +export async function getAccessTokenForViya( requestClient: RequestClient, clientId: string, clientSecret: string, diff --git a/src/auth/getTokens.ts b/src/auth/getTokens.ts index fe7779d..9dc0c1c 100644 --- a/src/auth/getTokens.ts +++ b/src/auth/getTokens.ts @@ -3,18 +3,21 @@ import { isRefreshTokenExpiring, hasTokenExpired } from '@sasjs/utils/auth' -import { AuthConfig } from '@sasjs/utils/types' +import { AuthConfig, ServerType } from '@sasjs/utils/types' import { RequestClient } from '../request/RequestClient' -import { refreshTokens } from './refreshTokens' +import { refreshTokensForViya } from './refreshTokensForViya' +import { refreshTokensForSasjs } from './refreshTokensForSasjs' /** * Returns the auth configuration, refreshing the tokens if necessary. * @param requestClient - the pre-configured HTTP request client * @param authConfig - an object containing a client ID, secret, access token and refresh token + * @param serverType - server type for which refreshing the tokens, defaults to SASVIYA */ export async function getTokens( requestClient: RequestClient, - authConfig: AuthConfig + authConfig: AuthConfig, + serverType: ServerType = ServerType.SasViya ): Promise { const logger = process.logger || console let { access_token, refresh_token, client, secret } = authConfig @@ -29,12 +32,16 @@ export async function getTokens( throw new Error(error) } logger.info('Refreshing access and refresh tokens.') - ;({ access_token, refresh_token } = await refreshTokens( - requestClient, - client, - secret, - refresh_token - )) + const tokens = + serverType === ServerType.SasViya + ? await refreshTokensForViya( + requestClient, + client, + secret, + refresh_token + ) + : await refreshTokensForSasjs(requestClient, refresh_token) + ;({ access_token, refresh_token } = tokens) } return { access_token, refresh_token, client, secret } } diff --git a/src/auth/refreshTokensForSasjs.ts b/src/auth/refreshTokensForSasjs.ts new file mode 100644 index 0000000..e6ed601 --- /dev/null +++ b/src/auth/refreshTokensForSasjs.ts @@ -0,0 +1,35 @@ +import { prefixMessage } from '@sasjs/utils/error' +import { RequestClient } from '../request/RequestClient' + +/** + * Exchanges the refresh token for an access token for the given client. + * @param requestClient - the pre-configured HTTP request client + * @param refreshToken - the refresh token received from the server. + */ +export async function refreshTokensForSasjs( + requestClient: RequestClient, + refreshToken: string +) { + const url = '/SASjsApi/auth/refresh' + const headers = { + Authorization: 'Bearer ' + refreshToken + } + + const authResponse = await requestClient + .post(url, undefined, undefined, undefined, headers) + .then((res) => { + const sasAuth = res.result as { + accessToken: string + refreshToken: string + } + return { + access_token: sasAuth.accessToken, + refresh_token: sasAuth.refreshToken + } + }) + .catch((err) => { + throw prefixMessage(err, 'Error while refreshing tokens') + }) + + return authResponse +} diff --git a/src/auth/refreshTokens.ts b/src/auth/refreshTokensForViya.ts similarity index 92% rename from src/auth/refreshTokens.ts rename to src/auth/refreshTokensForViya.ts index 5871d63..0826bc8 100644 --- a/src/auth/refreshTokens.ts +++ b/src/auth/refreshTokensForViya.ts @@ -8,9 +8,9 @@ import { RequestClient } from '../request/RequestClient' * @param requestClient - the pre-configured HTTP request client * @param clientId - the client ID to authenticate with. * @param clientSecret - the client secret to authenticate with. - * @param authCode - the refresh token received from the server. + * @param refreshToken - the refresh token received from the server. */ -export async function refreshTokens( +export async function refreshTokensForViya( requestClient: RequestClient, clientId: string, clientSecret: string, diff --git a/src/auth/spec/getAccessTokenForSasjs.spec.ts b/src/auth/spec/getAccessTokenForSasjs.spec.ts new file mode 100644 index 0000000..075d9b9 --- /dev/null +++ b/src/auth/spec/getAccessTokenForSasjs.spec.ts @@ -0,0 +1,65 @@ +import { AuthConfig } from '@sasjs/utils' +import { generateToken, mockSasjsAuthResponse } from './mockResponses' +import { RequestClient } from '../../request/RequestClient' +import { getAccessTokenForSasjs } from '../getAccessTokenForSasjs' + +const requestClient = new (>RequestClient)() + +describe('getAccessTokenForSasjs', () => { + it('should attempt to refresh tokens', async () => { + setupMocks() + const access_token = generateToken(30) + const refresh_token = generateToken(30) + const authConfig: AuthConfig = { + access_token, + refresh_token, + client: 'cl13nt', + secret: 's3cr3t' + } + jest + .spyOn(requestClient, 'post') + .mockImplementation(() => + Promise.resolve({ result: mockSasjsAuthResponse, etag: '' }) + ) + + await getAccessTokenForSasjs( + requestClient, + authConfig.client, + authConfig.refresh_token + ) + + expect(requestClient.post).toHaveBeenCalledWith( + '/SASjsApi/auth/token', + { clientId: authConfig.client, code: authConfig.refresh_token }, + undefined + ) + }) + + it('should handle errors while refreshing tokens', async () => { + setupMocks() + const access_token = generateToken(30) + const refresh_token = generateToken(30) + const authConfig: AuthConfig = { + access_token, + refresh_token, + client: 'cl13nt', + secret: 's3cr3t' + } + jest + .spyOn(requestClient, 'post') + .mockImplementation(() => Promise.reject('Token Error')) + + const error = await getAccessTokenForSasjs( + requestClient, + authConfig.client, + authConfig.refresh_token + ).catch((e) => e) + + expect(error).toContain('Error while getting access token') + }) +}) + +const setupMocks = () => { + jest.restoreAllMocks() + jest.mock('../../request/RequestClient') +} diff --git a/src/auth/spec/getAccessToken.spec.ts b/src/auth/spec/getAccessTokenForViya.spec.ts similarity index 91% rename from src/auth/spec/getAccessToken.spec.ts rename to src/auth/spec/getAccessTokenForViya.spec.ts index e4fa00f..a04f7ed 100644 --- a/src/auth/spec/getAccessToken.spec.ts +++ b/src/auth/spec/getAccessTokenForViya.spec.ts @@ -2,11 +2,11 @@ import { AuthConfig } from '@sasjs/utils' import * as NodeFormData from 'form-data' import { generateToken, mockAuthResponse } from './mockResponses' import { RequestClient } from '../../request/RequestClient' -import { getAccessToken } from '../getAccessToken' +import { getAccessTokenForViya } from '../getAccessTokenForViya' const requestClient = new (>RequestClient)() -describe('getAccessToken', () => { +describe('getAccessTokenForViya', () => { it('should attempt to refresh tokens', async () => { setupMocks() const access_token = generateToken(30) @@ -26,7 +26,7 @@ describe('getAccessToken', () => { authConfig.client + ':' + authConfig.secret ).toString('base64') - await getAccessToken( + await getAccessTokenForViya( requestClient, authConfig.client, authConfig.secret, @@ -58,7 +58,7 @@ describe('getAccessToken', () => { .spyOn(requestClient, 'post') .mockImplementation(() => Promise.reject('Token Error')) - const error = await getAccessToken( + const error = await getAccessTokenForViya( requestClient, authConfig.client, authConfig.secret, diff --git a/src/auth/spec/getTokens.spec.ts b/src/auth/spec/getTokens.spec.ts index de4397c..deee213 100644 --- a/src/auth/spec/getTokens.spec.ts +++ b/src/auth/spec/getTokens.spec.ts @@ -1,5 +1,5 @@ import { AuthConfig } from '@sasjs/utils' -import * as refreshTokensModule from '../refreshTokens' +import * as refreshTokensModule from '../refreshTokensForViya' import { generateToken, mockAuthResponse } from './mockResponses' import { getTokens } from '../getTokens' import { RequestClient } from '../../request/RequestClient' @@ -20,7 +20,7 @@ describe('getTokens', () => { await getTokens(requestClient, authConfig) - expect(refreshTokensModule.refreshTokens).toHaveBeenCalledWith( + expect(refreshTokensModule.refreshTokensForViya).toHaveBeenCalledWith( requestClient, authConfig.client, authConfig.secret, @@ -41,7 +41,7 @@ describe('getTokens', () => { await getTokens(requestClient, authConfig) - expect(refreshTokensModule.refreshTokens).toHaveBeenCalledWith( + expect(refreshTokensModule.refreshTokensForViya).toHaveBeenCalledWith( requestClient, authConfig.client, authConfig.secret, @@ -71,9 +71,9 @@ describe('getTokens', () => { const setupMocks = () => { jest.restoreAllMocks() jest.mock('../../request/RequestClient') - jest.mock('../refreshTokens') + jest.mock('../refreshTokensForViya') jest - .spyOn(refreshTokensModule, 'refreshTokens') + .spyOn(refreshTokensModule, 'refreshTokensForViya') .mockImplementation(() => Promise.resolve(mockAuthResponse)) } diff --git a/src/auth/spec/mockResponses.ts b/src/auth/spec/mockResponses.ts index 3bd6124..4aaad1d 100644 --- a/src/auth/spec/mockResponses.ts +++ b/src/auth/spec/mockResponses.ts @@ -13,6 +13,11 @@ export const mockAuthResponse: SasAuthResponse = { jti: 'test' } +export const mockSasjsAuthResponse = { + access_token: 'acc355', + refresh_token: 'r3fr35h' +} + export const generateToken = (timeToLiveSeconds: number): string => { const exp = new Date(new Date().getTime() + timeToLiveSeconds * 1000).getTime() / 1000 diff --git a/src/auth/spec/refreshTokensForSasjs.spec.ts b/src/auth/spec/refreshTokensForSasjs.spec.ts new file mode 100644 index 0000000..91eda07 --- /dev/null +++ b/src/auth/spec/refreshTokensForSasjs.spec.ts @@ -0,0 +1,47 @@ +import { generateToken, mockAuthResponse } from './mockResponses' +import { RequestClient } from '../../request/RequestClient' +import { refreshTokensForSasjs } from '../refreshTokensForSasjs' + +const requestClient = new (>RequestClient)() + +describe('refreshTokensForSasjs', () => { + it('should attempt to refresh tokens', async () => { + setupMocks() + const refresh_token = generateToken(30) + jest + .spyOn(requestClient, 'post') + .mockImplementation(() => + Promise.resolve({ result: mockAuthResponse, etag: '' }) + ) + + await refreshTokensForSasjs(requestClient, refresh_token) + + expect(requestClient.post).toHaveBeenCalledWith( + '/SASjsApi/auth/refresh', + undefined, + undefined, + undefined, + { Authorization: `Bearer ${refresh_token}` } + ) + }) + + it('should handle errors while refreshing tokens', async () => { + setupMocks() + const refresh_token = generateToken(30) + jest + .spyOn(requestClient, 'post') + .mockImplementation(() => Promise.reject('Token Error')) + + const error = await refreshTokensForSasjs( + requestClient, + refresh_token + ).catch((e) => e) + + expect(error).toContain('Error while refreshing tokens') + }) +}) + +const setupMocks = () => { + jest.restoreAllMocks() + jest.mock('../../request/RequestClient') +} diff --git a/src/auth/spec/refreshTokens.spec.ts b/src/auth/spec/refreshTokensForViya.spec.ts similarity index 91% rename from src/auth/spec/refreshTokens.spec.ts rename to src/auth/spec/refreshTokensForViya.spec.ts index 8f88f1d..3025cfa 100644 --- a/src/auth/spec/refreshTokens.spec.ts +++ b/src/auth/spec/refreshTokensForViya.spec.ts @@ -2,11 +2,11 @@ import { AuthConfig } from '@sasjs/utils' import * as NodeFormData from 'form-data' import { generateToken, mockAuthResponse } from './mockResponses' import { RequestClient } from '../../request/RequestClient' -import { refreshTokens } from '../refreshTokens' +import { refreshTokensForViya } from '../refreshTokensForViya' const requestClient = new (>RequestClient)() -describe('refreshTokens', () => { +describe('refreshTokensForViya', () => { it('should attempt to refresh tokens', async () => { setupMocks() const access_token = generateToken(30) @@ -26,7 +26,7 @@ describe('refreshTokens', () => { authConfig.client + ':' + authConfig.secret ).toString('base64') - await refreshTokens( + await refreshTokensForViya( requestClient, authConfig.client, authConfig.secret, @@ -58,7 +58,7 @@ describe('refreshTokens', () => { .spyOn(requestClient, 'post') .mockImplementation(() => Promise.reject('Token Error')) - const error = await refreshTokens( + const error = await refreshTokensForViya( requestClient, authConfig.client, authConfig.secret,