diff --git a/packages/data-services/src/request/axios.ts b/packages/data-services/src/request/axios.ts index 807cee8534..1b4bb6d73b 100644 --- a/packages/data-services/src/request/axios.ts +++ b/packages/data-services/src/request/axios.ts @@ -1,6 +1,6 @@ import axios from 'axios'; import { setAuthorization } from './request'; -import { handleResponseError } from './response'; +import { handleResponseError, handleResponse } from './response'; declare module 'axios' { interface AxiosRequestConfig { @@ -8,6 +8,10 @@ declare module 'axios' { * If true, request will send with Authorization header. */ withAuthorization?: boolean; + /** + * If true, indicate this request is refreshing token. + */ + refreshTokenRequest?: boolean; } } @@ -16,4 +20,4 @@ export const request = axios.create({ }); request.interceptors.request.use(setAuthorization); -request.interceptors.response.use(handleResponseError); +request.interceptors.response.use(handleResponse, handleResponseError); diff --git a/packages/data-services/src/request/request/authorization/authorization.ts b/packages/data-services/src/request/request/authorization/authorization.ts index b581bd5ac8..ec097df701 100644 --- a/packages/data-services/src/request/request/authorization/authorization.ts +++ b/packages/data-services/src/request/request/authorization/authorization.ts @@ -76,19 +76,7 @@ export async function setAuthorization(config: AxiosRequestConfig) { throw new Error('No authorization token.'); } if (isAccessTokenExpired(token.accessToken)) { - if (!refreshingToken) { - refreshingToken = login({ - type: 'Refresh', - token: token.refreshToken, - }); - } - const newToken = await refreshingToken; - token = { - accessToken: newToken.token, - refreshToken: newToken.refresh, - }; - setToken(token); - refreshingToken = undefined; + await refreshToken(); } if (!config.headers) { config.headers = {}; @@ -97,3 +85,23 @@ export async function setAuthorization(config: AxiosRequestConfig) { } return config; } + +export const refreshToken = async () => { + let token = getToken(); + if (!token) { + throw new Error('No authorization token.'); + } + if (!refreshingToken) { + refreshingToken = login({ + type: 'Refresh', + token: token.refreshToken, + }); + } + const newToken = await refreshingToken; + token = { + accessToken: newToken.token, + refreshToken: newToken.refresh, + }; + setToken(token); + refreshingToken = undefined; +}; diff --git a/packages/data-services/src/request/response/handle-error.ts b/packages/data-services/src/request/response/handle-error.ts index 5d9bee6a91..e4168691f9 100644 --- a/packages/data-services/src/request/response/handle-error.ts +++ b/packages/data-services/src/request/response/handle-error.ts @@ -1,8 +1,27 @@ -import type { AxiosResponse } from 'axios'; +import type { AxiosResponse, AxiosError } from 'axios'; import { ServiceError } from '../ServiceError'; +import { refreshToken } from '../request/authorization'; +import { request } from '../axios'; -export function handleResponseError(response: AxiosResponse) { - const { data, status } = response; +export async function handleResponseError(error: AxiosError) { + const { response, config, message } = error; + const status = response?.status; + + if (status === 401) { + if (!config) { + throw new ServiceError(message, status.toString()); + } + if (config.refreshTokenRequest) { + throw new ServiceError(message, status.toString()); + } + await refreshToken(); + return request({ ...config, refreshTokenRequest: true }); + } + return response; +} + +export async function handleResponse(response: AxiosResponse) { + const { status, data } = response; if (status === 200) { if (data.error) { // TODO - common error handling diff --git a/packages/data-services/src/request/response/index.ts b/packages/data-services/src/request/response/index.ts index 6180a3906c..94547c0213 100644 --- a/packages/data-services/src/request/response/index.ts +++ b/packages/data-services/src/request/response/index.ts @@ -1 +1 @@ -export { handleResponseError } from './handle-error'; +export { handleResponseError, handleResponse } from './handle-error';