diff --git a/api/cache/getLogStores.js b/api/cache/getLogStores.js index 2692b6933c..b678880b0d 100644 --- a/api/cache/getLogStores.js +++ b/api/cache/getLogStores.js @@ -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'), diff --git a/api/server/controllers/AuthController.js b/api/server/controllers/AuthController.js index 96cb526f9f..16ba409fdf 100644 --- a/api/server/controllers/AuthController.js +++ b/api/server/controllers/AuthController.js @@ -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 { diff --git a/packages/data-provider/src/api-endpoints.ts b/packages/data-provider/src/api-endpoints.ts index 51fdb4c830..d493497e3c 100644 --- a/packages/data-provider/src/api-endpoints.ts +++ b/packages/data-provider/src/api-endpoints.ts @@ -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'; diff --git a/packages/data-provider/src/data-service.ts b/packages/data-provider/src/data-service.ts index 6ccebb3121..2a3739e96a 100644 --- a/packages/data-provider/src/data-service.ts +++ b/packages/data-provider/src/data-service.ts @@ -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 => request.get(endpoints.userKeyQuery(name)); diff --git a/packages/data-provider/src/request.ts b/packages/data-provider/src/request.ts index ee2cafa33f..769cebdec2 100644 --- a/packages/data-provider/src/request.ts +++ b/packages/data-provider/src/request.ts @@ -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); }, );