fix: getLogStores Property and Handle 401 Error from Refresh Token Request (#1084)

* fix(getLogStores): correct wrong prop passed to keyv opts: duration -> ttl

* fix: edge case where we get a blank screen if the initially intercepted 401 error is from a refresh token request; in this case, make explicit to the server that we are retrying from a refreshToken request
This commit is contained in:
Danny Avila 2023-10-21 12:39:08 -04:00 committed by GitHub
parent abbc57a49a
commit 6cb561abcf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 33 additions and 27 deletions

View file

@ -19,7 +19,7 @@ const pending_req = isEnabled(USE_REDIS)
const namespaces = {
pending_req,
ban: new Keyv({ store: keyvMongo, namespace: 'bans', duration }),
ban: new Keyv({ store: keyvMongo, namespace: 'bans', ttl: duration }),
general: new Keyv({ store: logFile, namespace: 'violations' }),
concurrent: createViolationInstance('concurrent'),
non_browser: createViolationInstance('non_browser'),

View file

@ -106,6 +106,9 @@ const refreshController = async (req, res) => {
const token = await setAuthTokens(userId, res, session._id);
const userObj = user.toJSON();
res.status(200).send({ token, user: userObj });
} else if (req?.query?.retry) {
// Retrying from a refresh token request that failed (401)
res.status(403).send('No session found');
} else if (payload.exp < Date.now() / 1000) {
res.status(403).redirect('/login');
} else {

View file

@ -52,7 +52,7 @@ export const loginFacebook = () => '/api/auth/facebook';
export const loginGoogle = () => '/api/auth/google';
export const refreshToken = () => '/api/auth/refresh';
export const refreshToken = (retry?: boolean) => `/api/auth/refresh${retry ? '?retry=true' : ''}`;
export const requestPasswordReset = () => '/api/auth/requestPasswordReset';

View file

@ -125,7 +125,7 @@ export const register = (payload: t.TRegisterUser) => {
return request.post(endpoints.register(), payload);
};
export const refreshToken = () => request.post(endpoints.refreshToken());
export const refreshToken = (retry?: boolean) => request.post(endpoints.refreshToken(retry));
export const userKeyQuery = (name: string): Promise<t.TCheckUserKeyResponse> =>
request.get(endpoints.userKeyQuery(name));

View file

@ -23,44 +23,47 @@ axios.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config;
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
if (isRefreshing) {
try {
const token = await new Promise(function (resolve, reject) {
const token = await new Promise((resolve, reject) => {
failedQueue.push({ resolve, reject });
});
originalRequest.headers['Authorization'] = 'Bearer ' + token;
return await axios(originalRequest);
} catch (err) {
return await Promise.reject(err);
return Promise.reject(err);
}
}
originalRequest._retry = true;
isRefreshing = true;
return new Promise(function (resolve, reject) {
refreshToken()
.then(({ token }) => {
if (token) {
originalRequest.headers['Authorization'] = 'Bearer ' + token;
setTokenHeader(token);
window.dispatchEvent(new CustomEvent('tokenUpdated', { detail: token }));
processQueue(null, token);
resolve(axios(originalRequest));
} else {
window.location.href = '/login';
}
})
.catch((err) => {
processQueue(err, null);
reject(err);
})
.then(() => {
isRefreshing = false;
});
});
try {
const { token } = await refreshToken(
// Handle edge case where we get a blank screen if the initial 401 error is from a refresh token request
originalRequest.url?.includes('api/auth/refresh') ? true : false,
);
if (token) {
originalRequest.headers['Authorization'] = 'Bearer ' + token;
setTokenHeader(token);
window.dispatchEvent(new CustomEvent('tokenUpdated', { detail: token }));
processQueue(null, token);
return await axios(originalRequest);
} else {
window.location.href = '/login';
}
} catch (err) {
processQueue(err as AxiosError, null);
return Promise.reject(err);
} finally {
isRefreshing = false;
}
}
return Promise.reject(error);
},
);