I make certain requests via Axios via a pinia store. These requests are via a timer, multiple requests can be sent. My server works with tokens that need to be refreshed. I have written an interceptor that checks the expiration time of the access token and sends a refresh token before it is invalid. All requests that happen while I handle the refresh token are stored in an array. Now this works, but I do not return to where the request was made (pinia store), so the data is not adjusted.
import axios from 'axios';
import {useAuthStore} from "@/stores/Authentication/AppAuthStore.js";
import VueJwtDecode from 'vue-jwt-decode';
axios.defaults.baseURL = import.meta.env.VITE_API_ENDPOINT;
axios.defaults.maxRedirects = 0;
let refreshing_token = null;
let myTimeout= null;
let busy = false;
let requestArray = [];
const baseURL = import.meta.env.VITE_API_ENDPOINT;
axios.interceptors.request.use( async req =>{
if (req.url.endsWith("refresh")) {
// if we are making a refresh token call, return it to prevent infinite loop
return req;
}
const accesstoken = sessionStorage.getItem("accesstoken")
if (accesstoken){
req.headers.Authorization = `Bearer ${accesstoken}`;
//const {header,payload} = useJwt(accesstoken)
let user = VueJwtDecode.decode(accesstoken);
const isExpired = Date.now() >= ((user.exp * 1000) - 10000)
console.log(isExpired)
if (!isExpired) return req;
requestArray.push(req);
console.log("is expired");
/* refreshing_token = refreshing_token ? refreshing_token : refresh_token();
let res = await refreshing_token;
refreshing_token = null;
clearTimeout(myTimeout);*/
if (!busy){
busy = true;
const refreshtoken = sessionStorage.getItem("refreshtoken")
axios.post(baseURL + 'auth/refresh', {
refresh_token : refreshtoken
}).then((res) => {
console.log(res);
console.log("token refreshed : " + res.data.accesstoken);
const authappstore = useAuthStore()
authappstore.isAppOK = true;
sessionStorage.setItem("accesstoken",res.data.accesstoken);
sessionStorage.setItem("refreshtoken", res.data.refreshtoken);
req.headers.Authorization = `Bearer ${res.data.accesstoken}`;
if (requestArray.length !== 0) {
requestArray.forEach(x => {
try {
console.log(x);
axios(x)
} catch (e) {
console.log(e)
}
});
requestArray = [];
}
}) .catch((err) => {
const errStatus = err.statusCode || 500;
const errMsg = err.message || 'Something went wrong';
console.log(errMsg)
}) .finally(() => {
busy = false;
});
}
}
else {
return req
}
})
export default axios;
I have no idea how to do that?
I just provide an idea ,you need to wait for a new access token When a request's access token expired, and go on that request (not push them to an array), so we need to return a Promise in the request interceptors to make the request in a waiting status, and we need create a CustomEvent ,when the request of getRefreshToken completed ,the CustomEvent triggered, the Promise will be resolved at this time, and the request will go on.
import axios from 'axios';
import {
useAuthStore
} from "@/stores/Authentication/AppAuthStore.js";
import VueJwtDecode from 'vue-jwt-decode';
axios.defaults.baseURL =
import.meta.env.VITE_API_ENDPOINT;
axios.defaults.maxRedirects = 0;
let refreshing_token = null;
let myTimeout = null;
let busy = false;
const baseURL =
import.meta.env.VITE_API_ENDPOINT;
const getRefreshToken = new CustomEvent('getRefreshToken');
axios.interceptors.request.use(async req => {
if (req.url.endsWith("refresh")) {
// if we are making a refresh token call, return it to prevent infinite loop
return req;
}
const accesstoken = sessionStorage.getItem("accesstoken")
if (accesstoken) {
req.headers.Authorization = `Bearer ${accesstoken}`;
//const {header,payload} = useJwt(accesstoken)
let user = VueJwtDecode.decode(accesstoken);
const isExpired = Date.now() >= ((user.exp * 1000) - 10000)
console.log(isExpired)
if (!isExpired) return req;
return refresh(req)
} else {
return req
}
})
function refresh(req) {
if (!busy) {
busy = true;
const refreshtoken = sessionStorage.getItem("refreshtoken")
axios.post(baseURL + 'auth/refresh', {
refresh_token: refreshtoken
}).then((res) => {
console.log(res);
console.log("token refreshed : " + res.data.accesstoken);
const authappstore = useAuthStore()
authappstore.isAppOK = true;
sessionStorage.setItem("accesstoken", res.data.accesstoken);
sessionStorage.setItem("refreshtoken", res.data.refreshtoken);
window.dispatchEvent(getRefreshToken)
}).catch((err) => {
const errStatus = err.statusCode || 500;
const errMsg = err.message || 'Something went wrong';
console.log(errMsg)
}).finally(() => {
busy = false;
});
}
return new Promise(res => {
function send() {
const accesstoken = sessionStorage.getItem("accesstoken");
req.headers.Authorization = `Bearer ${accesstoken}`;
res(req)
window.removeEventListener('getRefreshToken', send)
}
window.addEventListener('getRefreshToken', send)
})
}