add refresh tokens on client
All checks were successful
Build and Deploy Frontend / build-and-deploy (push) Successful in 7s
All checks were successful
Build and Deploy Frontend / build-and-deploy (push) Successful in 7s
This commit is contained in:
@@ -5,13 +5,41 @@
|
||||
import axios from "axios";
|
||||
|
||||
const baseUrl: string = import.meta.env.DEV ? import.meta.env.VITE_DEV_API_URL : "https://app.vxbard.net/api"
|
||||
const api = axios.create({
|
||||
export const api = axios.create({
|
||||
baseURL: baseUrl
|
||||
});
|
||||
|
||||
api.interceptors.request.use(config => {
|
||||
type FailedRequest = { resolve: (token: string) => void, reject: (error: unknown) => void}
|
||||
let isRefreshing: boolean = false;
|
||||
let failedQueue: FailedRequest[] = [];
|
||||
|
||||
const token = localStorage.getItem("token");
|
||||
export const authStorage = {
|
||||
getAccessToken: () => localStorage.getItem("accessToken"),
|
||||
getRefreshToken: () => localStorage.getItem("refreshToken"),
|
||||
|
||||
setTokens: ({ accessToken, refreshToken } : { accessToken: string, refreshToken: string }) => {
|
||||
localStorage.setItem("accessToken", accessToken)
|
||||
localStorage.setItem("refreshToken", refreshToken)
|
||||
},
|
||||
|
||||
clear: () => {
|
||||
localStorage.removeItem("accessToken")
|
||||
localStorage.removeItem("refreshToken")
|
||||
}
|
||||
}
|
||||
|
||||
const processQueue = (error: unknown, token: string | null = null): void => {
|
||||
failedQueue.forEach(prom => {
|
||||
if (error) prom.reject(error);
|
||||
else prom.resolve(token as string);
|
||||
})
|
||||
failedQueue = [];
|
||||
}
|
||||
|
||||
// intercept on each request
|
||||
api.interceptors.request.use(config => { // add access token to request headers
|
||||
|
||||
const token = localStorage.getAccessToken();
|
||||
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
@@ -21,4 +49,42 @@ api.interceptors.request.use(config => {
|
||||
|
||||
});
|
||||
|
||||
// intercept on each response
|
||||
api.interceptors.response.use(response => response, async error => { // mainly for authentication refreshTokens
|
||||
const originalRequest = error.config;
|
||||
|
||||
// if un authorized then refresh the token
|
||||
if(error.response?.status === 401 && !originalRequest._retry) {
|
||||
if(isRefreshing) {
|
||||
return new Promise((resolve, reject) => {
|
||||
failedQueue.push({ resolve, reject })
|
||||
}).then(token => {
|
||||
originalRequest.headers.Authorization = `Bearer ${token}`;
|
||||
return api(originalRequest);
|
||||
}).catch(err => Promise.reject(err));
|
||||
}
|
||||
|
||||
originalRequest._retry = true;
|
||||
isRefreshing = true;
|
||||
const refreshToken = authStorage.getRefreshToken();
|
||||
try {
|
||||
// request refresh endpoint get back a new accessToken
|
||||
const res = await axios.post(`${baseUrl}/auth/refresh`, { refreshToken });
|
||||
const { accessToken, refreshToken: newRefresh } = res.data;
|
||||
authStorage.setTokens({ accessToken, refreshToken: newRefresh });
|
||||
processQueue(null, accessToken);
|
||||
originalRequest.headers.Authorization = `Bearer ${accessToken}`;
|
||||
return api(originalRequest);
|
||||
} catch (err) {
|
||||
processQueue(err, null);
|
||||
authStorage.clear()
|
||||
window.location.href = "/login";
|
||||
return Promise.reject(err);
|
||||
} finally {
|
||||
isRefreshing = false;
|
||||
}
|
||||
}
|
||||
return Promise.reject(error);
|
||||
})
|
||||
|
||||
export default api;
|
||||
|
||||
Reference in New Issue
Block a user