From ffdc8ab549c02d9623e949a5bb36259c614307de Mon Sep 17 00:00:00 2001 From: SteveGT96 Date: Tue, 19 Nov 2024 15:14:12 +0100 Subject: [PATCH] fix: Fix token refresh --- package-lock.json | 16 ++++++++++ package.json | 1 + src/libraries/apiUtils/wrapper.ts | 49 +++++++++++++++++++++---------- 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index 77e814107..666d35cd7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "@mui/x-date-pickers": "^7.11.0", "@redux-devtools/extension": "^3.3.0", "@reduxjs/toolkit": "^2.2.6", + "async-mutex": "^0.5.0", "browser-image-compression": "^2.0.2", "chart.js": "^3.9.1", "classnames": "^2.2.6", @@ -11853,6 +11854,21 @@ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", "dev": true }, + "node_modules/async-mutex": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.5.0.tgz", + "integrity": "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/async-mutex/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/asynciterator.prototype": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", diff --git a/package.json b/package.json index 46eef8123..5b852b501 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@mui/x-date-pickers": "^7.11.0", "@redux-devtools/extension": "^3.3.0", "@reduxjs/toolkit": "^2.2.6", + "async-mutex": "^0.5.0", "browser-image-compression": "^2.0.2", "chart.js": "^3.9.1", "classnames": "^2.2.6", diff --git a/src/libraries/apiUtils/wrapper.ts b/src/libraries/apiUtils/wrapper.ts index a77e933c7..6d1309dbc 100644 --- a/src/libraries/apiUtils/wrapper.ts +++ b/src/libraries/apiUtils/wrapper.ts @@ -1,32 +1,49 @@ +import { Mutex } from "async-mutex"; import { AUTH_KEY } from "consts"; import { LoginApi } from "generated"; import { saveAuthenticationDataToSession } from "libraries/authUtils/saveAuthenticationDataToSession"; -import { refreshTokenHasExpired } from "libraries/authUtils/tokenHasExpired"; +import { + refreshTokenHasExpired, + tokenHasExpired, +} from "libraries/authUtils/tokenHasExpired"; import { SessionStorage } from "libraries/storage/storage"; -import { Observable, throwError } from "rxjs"; +import { Observable, from, throwError } from "rxjs"; import { catchError, delay, switchMap, tap } from "rxjs/operators"; import { customConfiguration } from "./configuration"; +const mutex = new Mutex(); + const loginApi = new LoginApi(customConfiguration(false)); export function wrapper(callback: () => Observable): Observable { return callback().pipe( catchError((error) => { - const refreshToken = SessionStorage.read(AUTH_KEY)?.refreshToken; - if ( - error.status === 401 && - refreshToken && - !refreshTokenHasExpired(refreshToken) - ) { - return loginApi - .refreshToken({ - tokenRefreshRequest: { refreshToken }, - }) - .pipe( - tap(saveAuthenticationDataToSession), - delay(500), - switchMap(() => callback()) + if (error.status === 401) { + const refreshToken = SessionStorage.read(AUTH_KEY)?.refreshToken; + if ( + error.status === 401 && + refreshToken && + !refreshTokenHasExpired(refreshToken) + ) { + return from( + mutex.runExclusive(async () => { + const token = SessionStorage.read(AUTH_KEY)?.token; + if (token && !tokenHasExpired(token)) { + return callback().toPromise(); + } + return loginApi + .refreshToken({ + tokenRefreshRequest: { refreshToken }, + }) + .pipe( + tap(saveAuthenticationDataToSession), + delay(500), + switchMap(() => callback()) + ) + .toPromise(); + }) ); + } } return throwError(error); })