mirror of
https://github.com/sasjs/adapter.git
synced 2026-01-08 13:00:05 +00:00
feat: get access token & refresh tokens for server type SASJS
This commit is contained in:
@@ -22,8 +22,8 @@ import { pollJobState } from './api/viya/pollJobState'
|
|||||||
import { getTokens } from './auth/getTokens'
|
import { getTokens } from './auth/getTokens'
|
||||||
import { uploadTables } from './api/viya/uploadTables'
|
import { uploadTables } from './api/viya/uploadTables'
|
||||||
import { executeScript } from './api/viya/executeScript'
|
import { executeScript } from './api/viya/executeScript'
|
||||||
import { getAccessToken } from './auth/getAccessToken'
|
import { getAccessTokenForViya } from './auth/getAccessTokenForViya'
|
||||||
import { refreshTokens } from './auth/refreshTokens'
|
import { refreshTokensForViya } from './auth/refreshTokensForViya'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A client for interfacing with the SAS Viya REST API.
|
* A client for interfacing with the SAS Viya REST API.
|
||||||
@@ -534,21 +534,26 @@ export class SASViyaApiClient {
|
|||||||
clientSecret: string,
|
clientSecret: string,
|
||||||
authCode: string
|
authCode: string
|
||||||
): Promise<SasAuthResponse> {
|
): Promise<SasAuthResponse> {
|
||||||
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.
|
* Exchanges the refresh token for an access token for the given client.
|
||||||
* @param clientId - the client ID to authenticate with.
|
* @param clientId - the client ID to authenticate with.
|
||||||
* @param clientSecret - the client secret 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(
|
public async refreshTokens(
|
||||||
clientId: string,
|
clientId: string,
|
||||||
clientSecret: string,
|
clientSecret: string,
|
||||||
refreshToken: string
|
refreshToken: string
|
||||||
) {
|
) {
|
||||||
return refreshTokens(
|
return refreshTokensForViya(
|
||||||
this.requestClient,
|
this.requestClient,
|
||||||
clientId,
|
clientId,
|
||||||
clientSecret,
|
clientSecret,
|
||||||
|
|||||||
100
src/SASjs.ts
100
src/SASjs.ts
@@ -11,13 +11,14 @@ import {
|
|||||||
} from './types'
|
} from './types'
|
||||||
import { SASViyaApiClient } from './SASViyaApiClient'
|
import { SASViyaApiClient } from './SASViyaApiClient'
|
||||||
import { SAS9ApiClient } from './SAS9ApiClient'
|
import { SAS9ApiClient } from './SAS9ApiClient'
|
||||||
import { SASjsApiClient } from './SASjsApiClient'
|
import { SASjsApiClient, SASjsAuthResponse } from './SASjsApiClient'
|
||||||
import { AuthManager } from './auth'
|
import { AuthManager } from './auth'
|
||||||
import {
|
import {
|
||||||
ServerType,
|
ServerType,
|
||||||
MacroVar,
|
MacroVar,
|
||||||
AuthConfig,
|
AuthConfig,
|
||||||
ExtraResponseAttributes
|
ExtraResponseAttributes,
|
||||||
|
SasAuthResponse
|
||||||
} from '@sasjs/utils/types'
|
} from '@sasjs/utils/types'
|
||||||
import { RequestClient } from './request/RequestClient'
|
import { RequestClient } from './request/RequestClient'
|
||||||
import {
|
import {
|
||||||
@@ -53,7 +54,7 @@ export default class SASjs {
|
|||||||
private jobsPath: string = ''
|
private jobsPath: string = ''
|
||||||
private sasViyaApiClient: SASViyaApiClient | null = null
|
private sasViyaApiClient: SASViyaApiClient | null = null
|
||||||
private sas9ApiClient: SAS9ApiClient | null = null
|
private sas9ApiClient: SAS9ApiClient | null = null
|
||||||
private SASjsApiClient: SASjsApiClient | null = null
|
private sasJSApiClient: SASjsApiClient | null = null
|
||||||
private fileUploader: FileUploader | null = null
|
private fileUploader: FileUploader | null = null
|
||||||
private authManager: AuthManager | null = null
|
private authManager: AuthManager | null = null
|
||||||
private requestClient: RequestClient | null = null
|
private requestClient: RequestClient | null = null
|
||||||
@@ -80,7 +81,7 @@ export default class SASjs {
|
|||||||
userName: string,
|
userName: string,
|
||||||
password: string
|
password: string
|
||||||
) {
|
) {
|
||||||
this.isMethodSupported('executeScriptSAS9', ServerType.Sas9)
|
this.isMethodSupported('executeScriptSAS9', [ServerType.Sas9])
|
||||||
|
|
||||||
return await this.sas9ApiClient?.executeScript(
|
return await this.sas9ApiClient?.executeScript(
|
||||||
linesOfCode,
|
linesOfCode,
|
||||||
@@ -94,7 +95,7 @@ export default class SASjs {
|
|||||||
* @param accessToken - an access token for an authorized user.
|
* @param accessToken - an access token for an authorized user.
|
||||||
*/
|
*/
|
||||||
public async getComputeContexts(accessToken: string) {
|
public async getComputeContexts(accessToken: string) {
|
||||||
this.isMethodSupported('getComputeContexts', ServerType.SasViya)
|
this.isMethodSupported('getComputeContexts', [ServerType.SasViya])
|
||||||
|
|
||||||
return await this.sasViyaApiClient!.getComputeContexts(accessToken)
|
return await this.sasViyaApiClient!.getComputeContexts(accessToken)
|
||||||
}
|
}
|
||||||
@@ -104,7 +105,7 @@ export default class SASjs {
|
|||||||
* @param accessToken - an access token for an authorized user.
|
* @param accessToken - an access token for an authorized user.
|
||||||
*/
|
*/
|
||||||
public async getLauncherContexts(accessToken: string) {
|
public async getLauncherContexts(accessToken: string) {
|
||||||
this.isMethodSupported('getLauncherContexts', ServerType.SasViya)
|
this.isMethodSupported('getLauncherContexts', [ServerType.SasViya])
|
||||||
|
|
||||||
return await this.sasViyaApiClient!.getLauncherContexts(accessToken)
|
return await this.sasViyaApiClient!.getLauncherContexts(accessToken)
|
||||||
}
|
}
|
||||||
@@ -113,7 +114,7 @@ export default class SASjs {
|
|||||||
* Gets default(system) launcher contexts.
|
* Gets default(system) launcher contexts.
|
||||||
*/
|
*/
|
||||||
public getDefaultComputeContexts() {
|
public getDefaultComputeContexts() {
|
||||||
this.isMethodSupported('getDefaultComputeContexts', ServerType.SasViya)
|
this.isMethodSupported('getDefaultComputeContexts', [ServerType.SasViya])
|
||||||
|
|
||||||
return this.sasViyaApiClient!.getDefaultComputeContexts()
|
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.
|
* @param authConfig - an access token, refresh token, client and secret for an authorized user.
|
||||||
*/
|
*/
|
||||||
public async getExecutableContexts(authConfig: AuthConfig) {
|
public async getExecutableContexts(authConfig: AuthConfig) {
|
||||||
this.isMethodSupported('getExecutableContexts', ServerType.SasViya)
|
this.isMethodSupported('getExecutableContexts', [ServerType.SasViya])
|
||||||
|
|
||||||
return await this.sasViyaApiClient!.getExecutableContexts(authConfig)
|
return await this.sasViyaApiClient!.getExecutableContexts(authConfig)
|
||||||
}
|
}
|
||||||
@@ -145,7 +146,7 @@ export default class SASjs {
|
|||||||
accessToken: string,
|
accessToken: string,
|
||||||
authorizedUsers?: string[]
|
authorizedUsers?: string[]
|
||||||
) {
|
) {
|
||||||
this.isMethodSupported('createComputeContext', ServerType.SasViya)
|
this.isMethodSupported('createComputeContext', [ServerType.SasViya])
|
||||||
|
|
||||||
return await this.sasViyaApiClient!.createComputeContext(
|
return await this.sasViyaApiClient!.createComputeContext(
|
||||||
contextName,
|
contextName,
|
||||||
@@ -170,7 +171,7 @@ export default class SASjs {
|
|||||||
launchType: string,
|
launchType: string,
|
||||||
accessToken: string
|
accessToken: string
|
||||||
) {
|
) {
|
||||||
this.isMethodSupported('createLauncherContext', ServerType.SasViya)
|
this.isMethodSupported('createLauncherContext', [ServerType.SasViya])
|
||||||
|
|
||||||
return await this.sasViyaApiClient!.createLauncherContext(
|
return await this.sasViyaApiClient!.createLauncherContext(
|
||||||
contextName,
|
contextName,
|
||||||
@@ -191,7 +192,7 @@ export default class SASjs {
|
|||||||
editedContext: EditContextInput,
|
editedContext: EditContextInput,
|
||||||
accessToken?: string
|
accessToken?: string
|
||||||
) {
|
) {
|
||||||
this.isMethodSupported('editComputeContext', ServerType.SasViya)
|
this.isMethodSupported('editComputeContext', [ServerType.SasViya])
|
||||||
|
|
||||||
return await this.sasViyaApiClient!.editComputeContext(
|
return await this.sasViyaApiClient!.editComputeContext(
|
||||||
contextName,
|
contextName,
|
||||||
@@ -206,7 +207,7 @@ export default class SASjs {
|
|||||||
* @param accessToken - an access token for an authorized user.
|
* @param accessToken - an access token for an authorized user.
|
||||||
*/
|
*/
|
||||||
public async deleteComputeContext(contextName: string, accessToken?: string) {
|
public async deleteComputeContext(contextName: string, accessToken?: string) {
|
||||||
this.isMethodSupported('deleteComputeContext', ServerType.SasViya)
|
this.isMethodSupported('deleteComputeContext', [ServerType.SasViya])
|
||||||
|
|
||||||
return await this.sasViyaApiClient!.deleteComputeContext(
|
return await this.sasViyaApiClient!.deleteComputeContext(
|
||||||
contextName,
|
contextName,
|
||||||
@@ -224,7 +225,7 @@ export default class SASjs {
|
|||||||
contextName: string,
|
contextName: string,
|
||||||
accessToken?: string
|
accessToken?: string
|
||||||
) {
|
) {
|
||||||
this.isMethodSupported('getComputeContextByName', ServerType.SasViya)
|
this.isMethodSupported('getComputeContextByName', [ServerType.SasViya])
|
||||||
|
|
||||||
return await this.sasViyaApiClient!.getComputeContextByName(
|
return await this.sasViyaApiClient!.getComputeContextByName(
|
||||||
contextName,
|
contextName,
|
||||||
@@ -238,7 +239,7 @@ export default class SASjs {
|
|||||||
* @param accessToken - an access token for an authorized user.
|
* @param accessToken - an access token for an authorized user.
|
||||||
*/
|
*/
|
||||||
public async getComputeContextById(contextId: string, accessToken?: string) {
|
public async getComputeContextById(contextId: string, accessToken?: string) {
|
||||||
this.isMethodSupported('getComputeContextById', ServerType.SasViya)
|
this.isMethodSupported('getComputeContextById', [ServerType.SasViya])
|
||||||
|
|
||||||
return await this.sasViyaApiClient!.getComputeContextById(
|
return await this.sasViyaApiClient!.getComputeContextById(
|
||||||
contextId,
|
contextId,
|
||||||
@@ -247,7 +248,7 @@ export default class SASjs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async createSession(contextName: string, accessToken: string) {
|
public async createSession(contextName: string, accessToken: string) {
|
||||||
this.isMethodSupported('createSession', ServerType.SasViya)
|
this.isMethodSupported('createSession', [ServerType.SasViya])
|
||||||
|
|
||||||
return await this.sasViyaApiClient!.createSession(contextName, accessToken)
|
return await this.sasViyaApiClient!.createSession(contextName, accessToken)
|
||||||
}
|
}
|
||||||
@@ -267,7 +268,7 @@ export default class SASjs {
|
|||||||
authConfig?: AuthConfig,
|
authConfig?: AuthConfig,
|
||||||
debug?: boolean
|
debug?: boolean
|
||||||
) {
|
) {
|
||||||
this.isMethodSupported('executeScriptSASViya', ServerType.SasViya)
|
this.isMethodSupported('executeScriptSASViya', [ServerType.SasViya])
|
||||||
if (!contextName) {
|
if (!contextName) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Context name is undefined. Please set a `contextName` in your SASjs or override config.'
|
'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.
|
* @param accessToken - the access token to authorize the request.
|
||||||
*/
|
*/
|
||||||
public async getFolder(folderPath: string, accessToken?: string) {
|
public async getFolder(folderPath: string, accessToken?: string) {
|
||||||
this.isMethodSupported('getFolder', ServerType.SasViya)
|
this.isMethodSupported('getFolder', [ServerType.SasViya])
|
||||||
return await this.sasViyaApiClient!.getFolder(folderPath, accessToken)
|
return await this.sasViyaApiClient!.getFolder(folderPath, accessToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,7 +368,7 @@ export default class SASjs {
|
|||||||
* @param accessToken - an access token for authorizing the request.
|
* @param accessToken - an access token for authorizing the request.
|
||||||
*/
|
*/
|
||||||
public async deleteFolder(folderPath: string, accessToken: string) {
|
public async deleteFolder(folderPath: string, accessToken: string) {
|
||||||
this.isMethodSupported('deleteFolder', ServerType.SasViya)
|
this.isMethodSupported('deleteFolder', [ServerType.SasViya])
|
||||||
|
|
||||||
return await this.sasViyaApiClient?.deleteFolder(folderPath, accessToken)
|
return await this.sasViyaApiClient?.deleteFolder(folderPath, accessToken)
|
||||||
}
|
}
|
||||||
@@ -382,7 +383,7 @@ export default class SASjs {
|
|||||||
accessToken?: string,
|
accessToken?: string,
|
||||||
limit?: number
|
limit?: number
|
||||||
) {
|
) {
|
||||||
this.isMethodSupported('listFolder', ServerType.SasViya)
|
this.isMethodSupported('listFolder', [ServerType.SasViya])
|
||||||
|
|
||||||
return await this.sasViyaApiClient?.listFolder(
|
return await this.sasViyaApiClient?.listFolder(
|
||||||
sourceFolder,
|
sourceFolder,
|
||||||
@@ -404,7 +405,7 @@ export default class SASjs {
|
|||||||
targetFolderName: string,
|
targetFolderName: string,
|
||||||
accessToken: string
|
accessToken: string
|
||||||
) {
|
) {
|
||||||
this.isMethodSupported('moveFolder', ServerType.SasViya)
|
this.isMethodSupported('moveFolder', [ServerType.SasViya])
|
||||||
|
|
||||||
return await this.sasViyaApiClient?.moveFolder(
|
return await this.sasViyaApiClient?.moveFolder(
|
||||||
sourceFolder,
|
sourceFolder,
|
||||||
@@ -422,7 +423,7 @@ export default class SASjs {
|
|||||||
accessToken?: string,
|
accessToken?: string,
|
||||||
sasApiClient?: SASViyaApiClient
|
sasApiClient?: SASViyaApiClient
|
||||||
) {
|
) {
|
||||||
this.isMethodSupported('createJobDefinition', ServerType.SasViya)
|
this.isMethodSupported('createJobDefinition', [ServerType.SasViya])
|
||||||
|
|
||||||
if (sasApiClient)
|
if (sasApiClient)
|
||||||
return await sasApiClient!.createJobDefinition(
|
return await sasApiClient!.createJobDefinition(
|
||||||
@@ -442,7 +443,7 @@ export default class SASjs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async getAuthCode(clientId: string) {
|
public async getAuthCode(clientId: string) {
|
||||||
this.isMethodSupported('getAuthCode', ServerType.SasViya)
|
this.isMethodSupported('getAuthCode', [ServerType.SasViya])
|
||||||
|
|
||||||
return await this.sasViyaApiClient!.getAuthCode(clientId)
|
return await this.sasViyaApiClient!.getAuthCode(clientId)
|
||||||
}
|
}
|
||||||
@@ -457,8 +458,14 @@ export default class SASjs {
|
|||||||
clientId: string,
|
clientId: string,
|
||||||
clientSecret: string,
|
clientSecret: string,
|
||||||
authCode: string
|
authCode: string
|
||||||
) {
|
): Promise<SasAuthResponse | SASjsAuthResponse> {
|
||||||
this.isMethodSupported('getAccessToken', ServerType.SasViya)
|
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(
|
return await this.sasViyaApiClient!.getAccessToken(
|
||||||
clientId,
|
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(
|
public async refreshTokens(
|
||||||
clientId: string,
|
clientId: string,
|
||||||
clientSecret: string,
|
clientSecret: string,
|
||||||
refreshToken: string
|
refreshToken: string
|
||||||
) {
|
): Promise<SasAuthResponse | SASjsAuthResponse> {
|
||||||
this.isMethodSupported('refreshTokens', ServerType.SasViya)
|
this.isMethodSupported('refreshTokens', [
|
||||||
|
ServerType.SasViya,
|
||||||
|
ServerType.Sasjs
|
||||||
|
])
|
||||||
|
|
||||||
|
if (this.sasjsConfig.serverType === ServerType.Sasjs)
|
||||||
|
return await this.sasJSApiClient!.refreshTokens(refreshToken)
|
||||||
|
|
||||||
return await this.sasViyaApiClient!.refreshTokens(
|
return await this.sasViyaApiClient!.refreshTokens(
|
||||||
clientId,
|
clientId,
|
||||||
@@ -482,7 +501,7 @@ export default class SASjs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async deleteClient(clientId: string, accessToken: string) {
|
public async deleteClient(clientId: string, accessToken: string) {
|
||||||
this.isMethodSupported('deleteClient', ServerType.SasViya)
|
this.isMethodSupported('deleteClient', [ServerType.SasViya])
|
||||||
|
|
||||||
return await this.sasViyaApiClient!.deleteClient(clientId, accessToken)
|
return await this.sasViyaApiClient!.deleteClient(clientId, accessToken)
|
||||||
}
|
}
|
||||||
@@ -777,7 +796,7 @@ export default class SASjs {
|
|||||||
accessToken?: string,
|
accessToken?: string,
|
||||||
isForced = false
|
isForced = false
|
||||||
) {
|
) {
|
||||||
this.isMethodSupported('deployServicePack', ServerType.SasViya)
|
this.isMethodSupported('deployServicePack', [ServerType.SasViya])
|
||||||
|
|
||||||
let sasApiClient: any = null
|
let sasApiClient: any = null
|
||||||
if (serverUrl || appLoc) {
|
if (serverUrl || appLoc) {
|
||||||
@@ -832,11 +851,11 @@ export default class SASjs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async deployToSASjs(members: [FolderMember, ServiceMember]) {
|
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) {
|
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
|
...config
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isMethodSupported('startComputeJob', ServerType.SasViya)
|
this.isMethodSupported('startComputeJob', [ServerType.SasViya])
|
||||||
if (!config.contextName) {
|
if (!config.contextName) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Context name is undefined. Please set a `contextName` in your SASjs or override config.'
|
'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.sasjsConfig.serverType === ServerType.Sasjs) {
|
||||||
if (this.SASjsApiClient) {
|
if (this.sasJSApiClient) {
|
||||||
this.SASjsApiClient.setConfig(this.sasjsConfig.serverUrl)
|
this.sasJSApiClient.setConfig(this.sasjsConfig.serverUrl)
|
||||||
} else {
|
} else {
|
||||||
this.SASjsApiClient = new SASjsApiClient(
|
this.sasJSApiClient = new SASjsApiClient(
|
||||||
this.sasjsConfig.serverUrl,
|
this.sasjsConfig.serverUrl,
|
||||||
this.requestClient
|
this.requestClient
|
||||||
)
|
)
|
||||||
@@ -1117,12 +1136,15 @@ export default class SASjs {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private isMethodSupported(method: string, serverType: string) {
|
private isMethodSupported(method: string, serverTypes: ServerType[]) {
|
||||||
if (this.sasjsConfig.serverType !== serverType) {
|
if (
|
||||||
|
!this.sasjsConfig.serverType ||
|
||||||
|
!serverTypes.includes(this.sasjsConfig.serverType)
|
||||||
|
) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Method '${method}' is only supported on ${
|
`Method '${method}' is only supported on ${serverTypes.join(
|
||||||
serverType === ServerType.Sas9 ? 'SAS9' : 'SAS Viya'
|
', '
|
||||||
} servers.`
|
)} servers.`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { FolderMember, ServiceMember, ExecutionQuery } from './types'
|
import { FolderMember, ServiceMember, ExecutionQuery } from './types'
|
||||||
import { RequestClient } from './request/RequestClient'
|
import { RequestClient } from './request/RequestClient'
|
||||||
|
import { getAccessTokenForSasjs } from './auth/getAccessTokenForSasjs'
|
||||||
|
import { refreshTokensForSasjs } from './auth/refreshTokensForSasjs'
|
||||||
|
|
||||||
export class SASjsApiClient {
|
export class SASjsApiClient {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -36,4 +38,30 @@ export class SASjsApiClient {
|
|||||||
|
|
||||||
return Promise.resolve(result)
|
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<SASjsAuthResponse> {
|
||||||
|
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<SASjsAuthResponse> {
|
||||||
|
return refreshTokensForSasjs(this.requestClient, refreshToken)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo move to sasjs/utils
|
||||||
|
export interface SASjsAuthResponse {
|
||||||
|
access_token: string
|
||||||
|
refresh_token: string
|
||||||
}
|
}
|
||||||
|
|||||||
36
src/auth/getAccessTokenForSasjs.ts
Normal file
36
src/auth/getAccessTokenForSasjs.ts
Normal 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. ')
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ import { RequestClient } from '../request/RequestClient'
|
|||||||
* @param clientSecret - the client secret to authenticate with.
|
* @param clientSecret - the client secret to authenticate with.
|
||||||
* @param authCode - the auth code received from the server.
|
* @param authCode - the auth code received from the server.
|
||||||
*/
|
*/
|
||||||
export async function getAccessToken(
|
export async function getAccessTokenForViya(
|
||||||
requestClient: RequestClient,
|
requestClient: RequestClient,
|
||||||
clientId: string,
|
clientId: string,
|
||||||
clientSecret: string,
|
clientSecret: string,
|
||||||
@@ -3,18 +3,21 @@ import {
|
|||||||
isRefreshTokenExpiring,
|
isRefreshTokenExpiring,
|
||||||
hasTokenExpired
|
hasTokenExpired
|
||||||
} from '@sasjs/utils/auth'
|
} from '@sasjs/utils/auth'
|
||||||
import { AuthConfig } from '@sasjs/utils/types'
|
import { AuthConfig, ServerType } from '@sasjs/utils/types'
|
||||||
import { RequestClient } from '../request/RequestClient'
|
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.
|
* Returns the auth configuration, refreshing the tokens if necessary.
|
||||||
* @param requestClient - the pre-configured HTTP request client
|
* @param requestClient - the pre-configured HTTP request client
|
||||||
* @param authConfig - an object containing a client ID, secret, access token and refresh token
|
* @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(
|
export async function getTokens(
|
||||||
requestClient: RequestClient,
|
requestClient: RequestClient,
|
||||||
authConfig: AuthConfig
|
authConfig: AuthConfig,
|
||||||
|
serverType: ServerType = ServerType.SasViya
|
||||||
): Promise<AuthConfig> {
|
): Promise<AuthConfig> {
|
||||||
const logger = process.logger || console
|
const logger = process.logger || console
|
||||||
let { access_token, refresh_token, client, secret } = authConfig
|
let { access_token, refresh_token, client, secret } = authConfig
|
||||||
@@ -29,12 +32,16 @@ export async function getTokens(
|
|||||||
throw new Error(error)
|
throw new Error(error)
|
||||||
}
|
}
|
||||||
logger.info('Refreshing access and refresh tokens.')
|
logger.info('Refreshing access and refresh tokens.')
|
||||||
;({ access_token, refresh_token } = await refreshTokens(
|
const tokens =
|
||||||
requestClient,
|
serverType === ServerType.SasViya
|
||||||
client,
|
? await refreshTokensForViya(
|
||||||
secret,
|
requestClient,
|
||||||
refresh_token
|
client,
|
||||||
))
|
secret,
|
||||||
|
refresh_token
|
||||||
|
)
|
||||||
|
: await refreshTokensForSasjs(requestClient, refresh_token)
|
||||||
|
;({ access_token, refresh_token } = tokens)
|
||||||
}
|
}
|
||||||
return { access_token, refresh_token, client, secret }
|
return { access_token, refresh_token, client, secret }
|
||||||
}
|
}
|
||||||
|
|||||||
35
src/auth/refreshTokensForSasjs.ts
Normal file
35
src/auth/refreshTokensForSasjs.ts
Normal 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
|
||||||
|
}
|
||||||
@@ -8,9 +8,9 @@ import { RequestClient } from '../request/RequestClient'
|
|||||||
* @param requestClient - the pre-configured HTTP request client
|
* @param requestClient - the pre-configured HTTP request client
|
||||||
* @param clientId - the client ID to authenticate with.
|
* @param clientId - the client ID to authenticate with.
|
||||||
* @param clientSecret - the client secret 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,
|
requestClient: RequestClient,
|
||||||
clientId: string,
|
clientId: string,
|
||||||
clientSecret: string,
|
clientSecret: string,
|
||||||
65
src/auth/spec/getAccessTokenForSasjs.spec.ts
Normal file
65
src/auth/spec/getAccessTokenForSasjs.spec.ts
Normal 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')
|
||||||
|
}
|
||||||
@@ -2,11 +2,11 @@ import { AuthConfig } from '@sasjs/utils'
|
|||||||
import * as NodeFormData from 'form-data'
|
import * as NodeFormData from 'form-data'
|
||||||
import { generateToken, mockAuthResponse } from './mockResponses'
|
import { generateToken, mockAuthResponse } from './mockResponses'
|
||||||
import { RequestClient } from '../../request/RequestClient'
|
import { RequestClient } from '../../request/RequestClient'
|
||||||
import { getAccessToken } from '../getAccessToken'
|
import { getAccessTokenForViya } from '../getAccessTokenForViya'
|
||||||
|
|
||||||
const requestClient = new (<jest.Mock<RequestClient>>RequestClient)()
|
const requestClient = new (<jest.Mock<RequestClient>>RequestClient)()
|
||||||
|
|
||||||
describe('getAccessToken', () => {
|
describe('getAccessTokenForViya', () => {
|
||||||
it('should attempt to refresh tokens', async () => {
|
it('should attempt to refresh tokens', async () => {
|
||||||
setupMocks()
|
setupMocks()
|
||||||
const access_token = generateToken(30)
|
const access_token = generateToken(30)
|
||||||
@@ -26,7 +26,7 @@ describe('getAccessToken', () => {
|
|||||||
authConfig.client + ':' + authConfig.secret
|
authConfig.client + ':' + authConfig.secret
|
||||||
).toString('base64')
|
).toString('base64')
|
||||||
|
|
||||||
await getAccessToken(
|
await getAccessTokenForViya(
|
||||||
requestClient,
|
requestClient,
|
||||||
authConfig.client,
|
authConfig.client,
|
||||||
authConfig.secret,
|
authConfig.secret,
|
||||||
@@ -58,7 +58,7 @@ describe('getAccessToken', () => {
|
|||||||
.spyOn(requestClient, 'post')
|
.spyOn(requestClient, 'post')
|
||||||
.mockImplementation(() => Promise.reject('Token Error'))
|
.mockImplementation(() => Promise.reject('Token Error'))
|
||||||
|
|
||||||
const error = await getAccessToken(
|
const error = await getAccessTokenForViya(
|
||||||
requestClient,
|
requestClient,
|
||||||
authConfig.client,
|
authConfig.client,
|
||||||
authConfig.secret,
|
authConfig.secret,
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { AuthConfig } from '@sasjs/utils'
|
import { AuthConfig } from '@sasjs/utils'
|
||||||
import * as refreshTokensModule from '../refreshTokens'
|
import * as refreshTokensModule from '../refreshTokensForViya'
|
||||||
import { generateToken, mockAuthResponse } from './mockResponses'
|
import { generateToken, mockAuthResponse } from './mockResponses'
|
||||||
import { getTokens } from '../getTokens'
|
import { getTokens } from '../getTokens'
|
||||||
import { RequestClient } from '../../request/RequestClient'
|
import { RequestClient } from '../../request/RequestClient'
|
||||||
@@ -20,7 +20,7 @@ describe('getTokens', () => {
|
|||||||
|
|
||||||
await getTokens(requestClient, authConfig)
|
await getTokens(requestClient, authConfig)
|
||||||
|
|
||||||
expect(refreshTokensModule.refreshTokens).toHaveBeenCalledWith(
|
expect(refreshTokensModule.refreshTokensForViya).toHaveBeenCalledWith(
|
||||||
requestClient,
|
requestClient,
|
||||||
authConfig.client,
|
authConfig.client,
|
||||||
authConfig.secret,
|
authConfig.secret,
|
||||||
@@ -41,7 +41,7 @@ describe('getTokens', () => {
|
|||||||
|
|
||||||
await getTokens(requestClient, authConfig)
|
await getTokens(requestClient, authConfig)
|
||||||
|
|
||||||
expect(refreshTokensModule.refreshTokens).toHaveBeenCalledWith(
|
expect(refreshTokensModule.refreshTokensForViya).toHaveBeenCalledWith(
|
||||||
requestClient,
|
requestClient,
|
||||||
authConfig.client,
|
authConfig.client,
|
||||||
authConfig.secret,
|
authConfig.secret,
|
||||||
@@ -71,9 +71,9 @@ describe('getTokens', () => {
|
|||||||
const setupMocks = () => {
|
const setupMocks = () => {
|
||||||
jest.restoreAllMocks()
|
jest.restoreAllMocks()
|
||||||
jest.mock('../../request/RequestClient')
|
jest.mock('../../request/RequestClient')
|
||||||
jest.mock('../refreshTokens')
|
jest.mock('../refreshTokensForViya')
|
||||||
|
|
||||||
jest
|
jest
|
||||||
.spyOn(refreshTokensModule, 'refreshTokens')
|
.spyOn(refreshTokensModule, 'refreshTokensForViya')
|
||||||
.mockImplementation(() => Promise.resolve(mockAuthResponse))
|
.mockImplementation(() => Promise.resolve(mockAuthResponse))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ export const mockAuthResponse: SasAuthResponse = {
|
|||||||
jti: 'test'
|
jti: 'test'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const mockSasjsAuthResponse = {
|
||||||
|
access_token: 'acc355',
|
||||||
|
refresh_token: 'r3fr35h'
|
||||||
|
}
|
||||||
|
|
||||||
export const generateToken = (timeToLiveSeconds: number): string => {
|
export const generateToken = (timeToLiveSeconds: number): string => {
|
||||||
const exp =
|
const exp =
|
||||||
new Date(new Date().getTime() + timeToLiveSeconds * 1000).getTime() / 1000
|
new Date(new Date().getTime() + timeToLiveSeconds * 1000).getTime() / 1000
|
||||||
|
|||||||
47
src/auth/spec/refreshTokensForSasjs.spec.ts
Normal file
47
src/auth/spec/refreshTokensForSasjs.spec.ts
Normal 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')
|
||||||
|
}
|
||||||
@@ -2,11 +2,11 @@ import { AuthConfig } from '@sasjs/utils'
|
|||||||
import * as NodeFormData from 'form-data'
|
import * as NodeFormData from 'form-data'
|
||||||
import { generateToken, mockAuthResponse } from './mockResponses'
|
import { generateToken, mockAuthResponse } from './mockResponses'
|
||||||
import { RequestClient } from '../../request/RequestClient'
|
import { RequestClient } from '../../request/RequestClient'
|
||||||
import { refreshTokens } from '../refreshTokens'
|
import { refreshTokensForViya } from '../refreshTokensForViya'
|
||||||
|
|
||||||
const requestClient = new (<jest.Mock<RequestClient>>RequestClient)()
|
const requestClient = new (<jest.Mock<RequestClient>>RequestClient)()
|
||||||
|
|
||||||
describe('refreshTokens', () => {
|
describe('refreshTokensForViya', () => {
|
||||||
it('should attempt to refresh tokens', async () => {
|
it('should attempt to refresh tokens', async () => {
|
||||||
setupMocks()
|
setupMocks()
|
||||||
const access_token = generateToken(30)
|
const access_token = generateToken(30)
|
||||||
@@ -26,7 +26,7 @@ describe('refreshTokens', () => {
|
|||||||
authConfig.client + ':' + authConfig.secret
|
authConfig.client + ':' + authConfig.secret
|
||||||
).toString('base64')
|
).toString('base64')
|
||||||
|
|
||||||
await refreshTokens(
|
await refreshTokensForViya(
|
||||||
requestClient,
|
requestClient,
|
||||||
authConfig.client,
|
authConfig.client,
|
||||||
authConfig.secret,
|
authConfig.secret,
|
||||||
@@ -58,7 +58,7 @@ describe('refreshTokens', () => {
|
|||||||
.spyOn(requestClient, 'post')
|
.spyOn(requestClient, 'post')
|
||||||
.mockImplementation(() => Promise.reject('Token Error'))
|
.mockImplementation(() => Promise.reject('Token Error'))
|
||||||
|
|
||||||
const error = await refreshTokens(
|
const error = await refreshTokensForViya(
|
||||||
requestClient,
|
requestClient,
|
||||||
authConfig.client,
|
authConfig.client,
|
||||||
authConfig.secret,
|
authConfig.secret,
|
||||||
Reference in New Issue
Block a user