I am using axios-auth-refresh
axios interceptor 3rd party library to handle my refresh token, the issue is that i have multiple request on my dashboard around 10 request and every time when the token expires, it will execute the my refresh token function multiple times and based on how many requests that are made. I previously refer to this stackoverflow question but it didn't somehow work on me and some requests are not being made then I opt at using axios-auth-refresh
library to handle my refresh token function, because I thought that the option pauseInstanceWhileRefreshing: true
will help me prevent it but it didn't somehow work.
What I want to achieve is to execute a single refresh token request to the server while other requests are on queue (I am using cookie to store my token), once it successfully replace the token then it will retry or resend those request back to the server. Below is my code:
import axios from 'axios';
import axiosRetry from 'axios-retry';
import config from 'config';
import {isNull, isUndefined} from 'underscore';
import Cookies from 'universal-cookie';
import createAuthRefreshInterceptor from 'axios-auth-refresh';
const api_client = () => {
const client = axios.create({baseURL: config.server});
const cookies = new Cookies();
client.interceptors.request.use(request => {
const cookies = new Cookies();
const cookieToken = cookies.get('token');
const cookieUser = cookies.get('user');
if(!isNull(cookieToken) && !isNull(cookieUser)) {
if(!isUndefined(cookieToken.token)) {
request.headers['Authorization'] = `Bearer ${cookieToken.token}`;
}
request.withCredentials = true;
request.headers['Content-Type'] = 'application/json'
request.headers['X-Fname'] = cookieUser.username;
}
return request;
}, error => {
console.log(error);
});
const handleRefreshAuth = failedRequest => {
return getRefreshAuthToken().then(response => {
if(response.data) {
cookies.remove("token", { domain: window.location.hostname, path: "/grt" });
cookies.remove("token", { domain: window.location.hostname, path: "/" });
cookies.set("token", { token: response.data.token, refreshToken: response.data.refreshToken, }, { domain: window.location.hostname, path: "/grt", expires: new Date(Date.now() + 259200) });
failedRequest.response.config.headers['Authorization'] = `Bearer ${response.data.token}`;
return Promise.resolve();
}
})
}
const options = {
pauseInstanceWhileRefreshing: true
}
createAuthRefreshInterceptor(client, handleRefreshAuth, options);
const getRefreshAuthToken = () => {
return new Promise((resolve, reject) => {
const cookieToken = cookies.get('token');
const cookieUser = cookies.get('user');
if((!isNull(cookieToken) && !isNull(cookieUser)) || (!isUndefined(cookieToken) && !isUndefined(cookieUser))) {
client.post(`/user/refresh?refreshToken=${cookieToken.refreshToken}`).then(response => {
if(response) {
resolve(response)
}
})
}
})
}
return client;
}
export const retrieve = async (url, data = undefined) => {
return new Promise(async (resolve, reject) => {
await api_client().get(url, data).then(response => {
if(response) {
resolve(response.data);
}
})
})
}
export const send = async (url, data = undefined) => {
return new Promise(async (resolve, reject) => {
await api_client().post(url, data, { skipAuthRefresh: true }).then(response => {
if(response) {
resolve(response.data);
}
})
})
}
export default {retrieve, send};
Old code
I added this one as well, it might be that I missed something else on this one, using raw axios
interceptor method, same issue as the new one.
import axios from 'axios';
import axiosRetry from 'axios-retry';
import config from 'config';
import {isNull, isUndefined} from 'underscore';
import Cookies from 'universal-cookie';
const api_client = () => {
const client = axios.create({baseURL: config.server});
let isRefreshing = false;
let failedQueue = [];
const retryCodes = [
401
]
axiosRetry(client, {
retries: 3,
retryDelay: (retryCount) => {
return retryCount * 1000;
},
retryCondition: (error) => {
return retryCodes.includes(error.response.status);
}
});
client.interceptors.request.use(request => {
const cookies = new Cookies();
const cookieToken = cookies.get('token');
const cookieUser = cookies.get('user');
if(!isNull(cookieToken) && !isNull(cookieUser)) {
if(!isUndefined(cookieToken.token)) {
request.headers['Authorization'] = `Bearer ${cookieToken.token}`;
}
request.withCredentials = true;
request.headers['Content-Type'] = 'application/json'
request.headers['X-Fname'] = cookieUser.username;
}
return request;
}, error => {
console.log(error);
});
const processQueue = (error, token = null) => {
const cookies = new Cookies();
console.log('processQueue', token)
failedQueue.forEach(prom => {
if (error) {
prom.reject(error);
} else {
const cookieToken = cookies.get('token');
prom.resolve(cookieToken.token);
}
})
failedQueue = [];
}
const getRefreshAuthToken = async () => {
return new Promise(async (resolve, reject) => {
const cookies = new Cookies();
const cookieToken = cookies.get('token');
const cookieUser = cookies.get('user');
if((!isNull(cookieToken) && !isNull(cookieUser)) || (!isUndefined(cookieToken) && !isUndefined(cookieUser))) {
await client.post(`/user/refresh?refreshToken=${cookieToken.refreshToken}`).then(response => {
if(response) {
resolve(response)
}
})
}
})
}
client.interceptors.response.use(response => {
return response;
}, error => {
const originalRequest = error.config;
const cookies = new Cookies();
if (error.response.status === 401 && !originalRequest._retry) {
if (isRefreshing) {
return new Promise(function(resolve, reject) {
failedQueue.push({ resolve, reject });
}).then(response => {
if(response) {
console.log('from test response', response)
cookies.remove("token", { domain: window.location.hostname, path: "/grt" });
cookies.remove("token", { domain: window.location.hostname, path: "/" });
cookies.set("token", { token: response.data.token, refreshToken: response.data.refreshToken, }, { domain: window.location.hostname, path: "/grt", expires: new Date(Date.now() + 259200) });
originalRequest.headers['Authorization'] = `Bearer ${cookies.get('token').token}`;
return client(originalRequest);
}
}).catch(error => {
return Promise.reject(error);
});
}
originalRequest._retry = true;
isRefreshing = true;
return new Promise((resolve, reject) => {
getRefreshAuthToken()
.then(response => {
if(!isUndefined(response)) {
cookies.remove("token", { domain: window.location.hostname, path: "/grt" });
cookies.remove("token", { domain: window.location.hostname, path: "/" });
cookies.set("token", { token: response.data.token, refreshToken: response.data.refreshToken, }, { domain: window.location.hostname, path: "/grt", expires: new Date(Date.now() + 259200) });
}
processQueue(null, cookies.get('token').token);
resolve(client(originalRequest));
}).catch(error => {
// add to queue for failed requests
processQueue(error, null);
reject(error);
}).then(() => {
isRefreshing = false
});
});
}
return Promise.reject(error);
})
return client;
}
export const retrieve = async (url, data = undefined) => {
return new Promise(async (resolve, reject) => {
await api_client().get(url, data).then(response => {
if(response) {
resolve(response.data);
}
})
})
}
export const send = async (url, data = undefined) => {
return new Promise(async (resolve, reject) => {
await api_client().post(url, data, { skipAuthRefresh: true }).then(response => {
if(response) {
resolve(response.data);
}
})
})
}
export default {retrieve, send};
Does anyone knows how to fix this? If so, please let me know, thanks!