1
0
mirror of https://github.com/sasjs/adapter.git synced 2026-01-09 21:30:05 +00:00

feat: get access token & refresh tokens for server type SASJS

This commit is contained in:
Saad Jutt
2021-12-09 11:43:50 +05:00
parent b645d1495b
commit ebe9c2ffeb
14 changed files with 319 additions and 69 deletions

View File

@@ -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. ')
})
}

View File

@@ -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,

View File

@@ -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<AuthConfig> {
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 }
}

View File

@@ -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
}

View File

@@ -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,

View File

@@ -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 (<jest.Mock<RequestClient>>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')
}

View File

@@ -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 (<jest.Mock<RequestClient>>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,

View File

@@ -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))
}

View File

@@ -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

View File

@@ -0,0 +1,47 @@
import { generateToken, mockAuthResponse } from './mockResponses'
import { RequestClient } from '../../request/RequestClient'
import { refreshTokensForSasjs } from '../refreshTokensForSasjs'
const requestClient = new (<jest.Mock<RequestClient>>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')
}

View File

@@ -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 (<jest.Mock<RequestClient>>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,