mirror of
https://github.com/sasjs/adapter.git
synced 2026-01-02 02:00:06 +00:00
feat(get-token): improved error prefix
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
import { prefixMessage } from '@sasjs/utils/error'
|
import { prefixMessage } from '@sasjs/utils/error'
|
||||||
import { RequestClient } from '../request/RequestClient'
|
import { RequestClient } from '../request/RequestClient'
|
||||||
|
import { getTokenRequestErrorPrefix } from './getTokenRequestErrorPrefix'
|
||||||
|
import { ServerType } from '@sasjs/utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exchanges the auth code for an access token for the given client.
|
* Exchanges the auth code for an access token for the given client.
|
||||||
@@ -31,6 +33,16 @@ export async function getAccessTokenForSasjs(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw prefixMessage(err, 'Error while getting access token. ')
|
throw prefixMessage(
|
||||||
|
err,
|
||||||
|
getTokenRequestErrorPrefix(
|
||||||
|
'fetching access token',
|
||||||
|
'getAccessTokenForSasjs',
|
||||||
|
ServerType.Sasjs,
|
||||||
|
url,
|
||||||
|
data,
|
||||||
|
clientId
|
||||||
|
)
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { SasAuthResponse } from '@sasjs/utils/types'
|
import { SasAuthResponse, ServerType } from '@sasjs/utils/types'
|
||||||
import { prefixMessage } from '@sasjs/utils/error'
|
import { prefixMessage } from '@sasjs/utils/error'
|
||||||
import { RequestClient } from '../request/RequestClient'
|
import { RequestClient } from '../request/RequestClient'
|
||||||
import { CertificateError } from '../types/errors'
|
import { CertificateError } from '../types/errors'
|
||||||
|
import { getTokenRequestErrorPrefix } from './getTokenRequestErrorPrefix'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exchanges the auth code for an access token for the given client.
|
* Exchange the auth code for access / refresh tokens for the given client / secret pair.
|
||||||
* @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 auth code received from the server.
|
* @param authCode - the auth code received from the server.
|
||||||
@@ -16,29 +17,44 @@ export async function getAccessTokenForViya(
|
|||||||
clientSecret: string,
|
clientSecret: string,
|
||||||
authCode: string
|
authCode: string
|
||||||
): Promise<SasAuthResponse> {
|
): Promise<SasAuthResponse> {
|
||||||
const url = '/SASLogon/oauth/token'
|
|
||||||
let token
|
let token
|
||||||
|
|
||||||
if (typeof Buffer === 'undefined') {
|
if (typeof Buffer === 'undefined') {
|
||||||
token = btoa(clientId + ':' + clientSecret)
|
token = btoa(clientId + ':' + clientSecret)
|
||||||
} else {
|
} else {
|
||||||
token = Buffer.from(clientId + ':' + clientSecret).toString('base64')
|
token = Buffer.from(clientId + ':' + clientSecret).toString('base64')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const url = '/SASLogon/oauth/token'
|
||||||
const headers = {
|
const headers = {
|
||||||
Authorization: 'Basic ' + token,
|
Authorization: 'Basic ' + token,
|
||||||
Accept: 'application/json'
|
Accept: 'application/json'
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = new URLSearchParams({
|
const dataJson = new URLSearchParams({
|
||||||
grant_type: 'authorization_code',
|
grant_type: 'authorization_code',
|
||||||
code: authCode
|
code: authCode
|
||||||
})
|
})
|
||||||
|
const data = new URLSearchParams(dataJson)
|
||||||
|
|
||||||
const authResponse = await requestClient
|
const authResponse = await requestClient
|
||||||
.post(url, data, undefined, 'application/x-www-form-urlencoded', headers)
|
.post(url, data, undefined, 'application/x-www-form-urlencoded', headers)
|
||||||
.then((res) => res.result as SasAuthResponse)
|
.then((res) => res.result as SasAuthResponse)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
if (err instanceof CertificateError) throw err
|
if (err instanceof CertificateError) throw err
|
||||||
throw prefixMessage(err, 'Error while getting access token. ')
|
throw prefixMessage(
|
||||||
|
err,
|
||||||
|
getTokenRequestErrorPrefix(
|
||||||
|
'fetching access token',
|
||||||
|
'getAccessTokenForViya',
|
||||||
|
ServerType.SasViya,
|
||||||
|
url,
|
||||||
|
dataJson,
|
||||||
|
headers,
|
||||||
|
clientId,
|
||||||
|
clientSecret
|
||||||
|
)
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
return authResponse
|
return authResponse
|
||||||
|
|||||||
88
src/auth/getTokenRequestErrorPrefix.ts
Normal file
88
src/auth/getTokenRequestErrorPrefix.ts
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import { ServerType } from '@sasjs/utils/types'
|
||||||
|
|
||||||
|
type Server = ServerType.SasViya | ServerType.Sasjs
|
||||||
|
type Operation = 'fetching access token' | 'refreshing tokens'
|
||||||
|
|
||||||
|
const getServerName = (server: Server) =>
|
||||||
|
server === ServerType.SasViya ? 'Viya' : 'Sasjs'
|
||||||
|
|
||||||
|
const getResponseTitle = (server: Server) =>
|
||||||
|
`Response from ${getServerName(server)} is below.`
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forms error prefix for requests related to token operations.
|
||||||
|
* @param operation - string describing operation ('fetching access token' or 'refreshing tokens').
|
||||||
|
* @param funcName - name of the function sent the request.
|
||||||
|
* @param server - server type (SASVIYA or SASJS).
|
||||||
|
* @param url - endpoint used to send the request.
|
||||||
|
* @param data - request payload.
|
||||||
|
* @param headers - request headers.
|
||||||
|
* @param clientId - client ID to authenticate with.
|
||||||
|
* @param clientSecret - client secret to authenticate with.
|
||||||
|
* @returns - string containing request information. Example:
|
||||||
|
* Error while fetching access token from /SASLogon/oauth/token
|
||||||
|
* Thrown by the @sasjs/adapter getAccessTokenForViya function.
|
||||||
|
* Payload:
|
||||||
|
* {
|
||||||
|
* "grant_type": "authorization_code",
|
||||||
|
* "code": "example_code"
|
||||||
|
* }
|
||||||
|
* Headers:
|
||||||
|
* {
|
||||||
|
* "Authorization": "Basic NEdMQXBwOjRHTEFwcDE=",
|
||||||
|
* "Accept": "application/json"
|
||||||
|
* }
|
||||||
|
* ClientId: exampleClientId
|
||||||
|
* ClientSecret: exampleClientSecret
|
||||||
|
*
|
||||||
|
* Response from Viya is below.
|
||||||
|
* Auth error: {
|
||||||
|
* "error": "invalid_token",
|
||||||
|
* "error_description": "No scopes were granted"
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export const getTokenRequestErrorPrefix = (
|
||||||
|
operation: Operation,
|
||||||
|
funcName: string,
|
||||||
|
server: Server,
|
||||||
|
url: string,
|
||||||
|
data?: {},
|
||||||
|
headers?: {},
|
||||||
|
clientId?: string,
|
||||||
|
clientSecret?: string
|
||||||
|
) => {
|
||||||
|
const stringify = (obj: {}) => JSON.stringify(obj, null, 2)
|
||||||
|
|
||||||
|
const lines = [
|
||||||
|
`Error while ${operation} from ${url}`,
|
||||||
|
`Thrown by the @sasjs/adapter ${funcName} function.`
|
||||||
|
]
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
lines.push('Payload:')
|
||||||
|
lines.push(stringify(data))
|
||||||
|
}
|
||||||
|
if (headers) {
|
||||||
|
lines.push('Headers:')
|
||||||
|
lines.push(stringify(headers))
|
||||||
|
}
|
||||||
|
if (clientId) lines.push(`ClientId: ${clientId}`)
|
||||||
|
if (clientSecret) lines.push(`ClientSecret: ${clientSecret}`)
|
||||||
|
|
||||||
|
lines.push('')
|
||||||
|
lines.push(`${getResponseTitle(server)}`)
|
||||||
|
lines.push('')
|
||||||
|
|
||||||
|
return lines.join(`\n`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse error prefix to get response payload.
|
||||||
|
* @param prefix - error prefix generated by getTokenRequestErrorPrefix function.
|
||||||
|
* @param server - server type (SASVIYA or SASJS).
|
||||||
|
* @returns - response payload.
|
||||||
|
*/
|
||||||
|
export const getTokenRequestErrorPrefixResponse = (
|
||||||
|
prefix: string,
|
||||||
|
server: ServerType.SasViya | ServerType.Sasjs
|
||||||
|
) => prefix.split(`${getResponseTitle(server)}\n`).pop() as string
|
||||||
@@ -22,6 +22,7 @@ export async function getTokens(
|
|||||||
): 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
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isAccessTokenExpiring(access_token) ||
|
isAccessTokenExpiring(access_token) ||
|
||||||
isRefreshTokenExpiring(refresh_token)
|
isRefreshTokenExpiring(refresh_token)
|
||||||
@@ -29,6 +30,7 @@ export async function getTokens(
|
|||||||
if (hasTokenExpired(refresh_token)) {
|
if (hasTokenExpired(refresh_token)) {
|
||||||
const error =
|
const error =
|
||||||
'Unable to obtain new access token. Your refresh token has expired.'
|
'Unable to obtain new access token. Your refresh token has expired.'
|
||||||
|
|
||||||
logger.error(error)
|
logger.error(error)
|
||||||
|
|
||||||
throw new Error(error)
|
throw new Error(error)
|
||||||
@@ -47,5 +49,6 @@ export async function getTokens(
|
|||||||
: await refreshTokensForSasjs(requestClient, refresh_token)
|
: await refreshTokensForSasjs(requestClient, refresh_token)
|
||||||
;({ access_token, refresh_token } = tokens)
|
;({ access_token, refresh_token } = tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
return { access_token, refresh_token, client, secret }
|
return { access_token, refresh_token, client, secret }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { prefixMessage } from '@sasjs/utils/error'
|
import { prefixMessage } from '@sasjs/utils/error'
|
||||||
import { RequestClient } from '../request/RequestClient'
|
import { RequestClient } from '../request/RequestClient'
|
||||||
|
import { getTokenRequestErrorPrefix } from './getTokenRequestErrorPrefix'
|
||||||
|
import { ServerType } from '@sasjs/utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exchanges the refresh token for an access token for the given client.
|
* Exchanges the refresh token for an access token for the given client.
|
||||||
@@ -28,7 +30,15 @@ export async function refreshTokensForSasjs(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw prefixMessage(err, 'Error while refreshing tokens: ')
|
throw prefixMessage(
|
||||||
|
err,
|
||||||
|
getTokenRequestErrorPrefix(
|
||||||
|
'refreshing tokens',
|
||||||
|
'refreshTokensForSasjs',
|
||||||
|
ServerType.Sasjs,
|
||||||
|
url
|
||||||
|
)
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
return authResponse
|
return authResponse
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { SasAuthResponse } from '@sasjs/utils/types'
|
import { SasAuthResponse, ServerType } from '@sasjs/utils/types'
|
||||||
import { prefixMessage } from '@sasjs/utils/error'
|
import { prefixMessage } from '@sasjs/utils/error'
|
||||||
import * as NodeFormData from 'form-data'
|
import * as NodeFormData from 'form-data'
|
||||||
import { RequestClient } from '../request/RequestClient'
|
import { RequestClient } from '../request/RequestClient'
|
||||||
import { isNode } from '../utils'
|
import { isNode } from '../utils'
|
||||||
|
import { getTokenRequestErrorPrefix } from './getTokenRequestErrorPrefix'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exchanges the refresh token for an access token for the given client.
|
* Exchanges the refresh token for an access token for the given client.
|
||||||
@@ -46,7 +47,19 @@ export async function refreshTokensForViya(
|
|||||||
)
|
)
|
||||||
.then((res) => res.result)
|
.then((res) => res.result)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw prefixMessage(err, 'Error while refreshing tokens: ')
|
throw prefixMessage(
|
||||||
|
err,
|
||||||
|
getTokenRequestErrorPrefix(
|
||||||
|
'refreshing tokens',
|
||||||
|
'refreshTokensForViya',
|
||||||
|
ServerType.SasViya,
|
||||||
|
url,
|
||||||
|
formData,
|
||||||
|
headers,
|
||||||
|
clientId,
|
||||||
|
clientSecret
|
||||||
|
)
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
return authResponse
|
return authResponse
|
||||||
|
|||||||
Reference in New Issue
Block a user