From bfa0879fed189398b6a6e6003becc132cb48bdb3 Mon Sep 17 00:00:00 2001 From: Matheus Tavares Frigo Date: Thu, 24 Jul 2025 12:04:40 -0300 Subject: [PATCH 1/2] fix: prevent infinite loop on renew token flow --- packages/oidc-client/src/renewTokens.ts | 30 ++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/packages/oidc-client/src/renewTokens.ts b/packages/oidc-client/src/renewTokens.ts index dffd14bd7..3e8262a9f 100644 --- a/packages/oidc-client/src/renewTokens.ts +++ b/packages/oidc-client/src/renewTokens.ts @@ -204,6 +204,7 @@ const synchroniseTokensAsync = forceRefresh = false, extras: StringMap = null, scope: string = null, + hiddenRetryCount = 0, ) => { if (!navigator.onLine && document.hidden) { return { tokens: oidc.tokens, status: 'GIVE_UP' }; @@ -217,9 +218,20 @@ const synchroniseTokensAsync = }); } const isDocumentHidden = document.hidden; - const nextIndex = isDocumentHidden ? index : index + 1; - if (index > 4) { + const nextIndex = index + 1; + const nextHiddenRetryCount = isDocumentHidden ? hiddenRetryCount + 1 : hiddenRetryCount; + + const shouldGiveUp = index > 4 || (isDocumentHidden && hiddenRetryCount > 10); + + if (shouldGiveUp) { if (isDocumentHidden) { + if (hiddenRetryCount > 10) { + updateTokens(null); + oidc.publishEvent(eventNames.refreshTokensAsync_error, { + message: 'refresh token failed after max hidden retries', + }); + return { tokens: null, status: 'SESSION_LOST' }; + } return { tokens: oidc.tokens, status: 'GIVE_UP' }; } else { updateTokens(null); @@ -227,6 +239,7 @@ const synchroniseTokensAsync = return { tokens: null, status: 'SESSION_LOST' }; } } + if (!extras) { extras = {}; } @@ -275,6 +288,7 @@ const synchroniseTokensAsync = return { tokens: silent_token_response.tokens, status: 'LOGGED' }; } catch (exceptionSilent: any) { console.error(exceptionSilent); + oidc.publishEvent(eventNames.refreshTokensAsync_silent_error, { message: 'exceptionSilent', exception: exceptionSilent.message, @@ -285,6 +299,7 @@ const synchroniseTokensAsync = forceRefresh, extras, scope, + nextHiddenRetryCount, ); } }; @@ -448,6 +463,7 @@ const synchroniseTokensAsync = forceRefresh, extras, scope, + nextHiddenRetryCount, ); } }; @@ -456,6 +472,7 @@ const synchroniseTokensAsync = } } catch (exception: any) { console.error(exception); + oidc.publishEvent(eventNames.refreshTokensAsync_silent_error, { message: 'exception', exception: exception.message, @@ -465,7 +482,14 @@ const synchroniseTokensAsync = // so we need to brake calls chain and delay next call return new Promise((resolve, reject) => { setTimeout(() => { - synchroniseTokensAsync(oidc)(updateTokens, nextIndex, forceRefresh, extras, scope) + synchroniseTokensAsync(oidc)( + updateTokens, + nextIndex, + forceRefresh, + extras, + scope, + nextHiddenRetryCount, + ) .then(resolve) .catch(reject); }, 1000); From b42aff46c4038622d5268b2280d5f9fe48a6a6ec Mon Sep 17 00:00:00 2001 From: Matheus Tavares Frigo Date: Fri, 25 Jul 2025 10:08:13 -0300 Subject: [PATCH 2/2] feat: refatoring background tries and removing GIVE_UP --- packages/oidc-client/package.json | 4 +- packages/oidc-client/src/renewTokens.ts | 52 +++++++++++-------------- 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/packages/oidc-client/package.json b/packages/oidc-client/package.json index 7f916a1ec..2aed0869f 100644 --- a/packages/oidc-client/package.json +++ b/packages/oidc-client/package.json @@ -1,6 +1,6 @@ { "name": "@axa-fr/oidc-client", - "version": "7.25.13", + "version": "7.25.14", "private": false, "type": "module", "main": "./dist/index.umd.cjs", @@ -57,4 +57,4 @@ "access": "public", "registry": "https://registry.npmjs.org/" } -} +} \ No newline at end of file diff --git a/packages/oidc-client/src/renewTokens.ts b/packages/oidc-client/src/renewTokens.ts index 3e8262a9f..c9e957729 100644 --- a/packages/oidc-client/src/renewTokens.ts +++ b/packages/oidc-client/src/renewTokens.ts @@ -20,6 +20,7 @@ async function syncTokens( const { tokens, status } = await synchroniseTokensAsync(oidc)( updateTokens, 0, + 0, forceRefresh, extras, scope, @@ -200,16 +201,19 @@ const synchroniseTokensAsync = (oidc: Oidc) => async ( updateTokens, - index = 0, + tryNumber = 0, + backgroundTry = 0, forceRefresh = false, extras: StringMap = null, scope: string = null, - hiddenRetryCount = 0, ) => { if (!navigator.onLine && document.hidden) { return { tokens: oidc.tokens, status: 'GIVE_UP' }; } let numberTryOnline = 6; + const maxTries = 5; + const maxBackgroundTries = 5; + while (!navigator.onLine && numberTryOnline > 0) { await sleepAsync({ milliseconds: 1000 }); numberTryOnline--; @@ -218,26 +222,13 @@ const synchroniseTokensAsync = }); } const isDocumentHidden = document.hidden; - const nextIndex = index + 1; - const nextHiddenRetryCount = isDocumentHidden ? hiddenRetryCount + 1 : hiddenRetryCount; - - const shouldGiveUp = index > 4 || (isDocumentHidden && hiddenRetryCount > 10); + const nextTry = isDocumentHidden ? tryNumber : tryNumber + 1; + const nextBackgroundTry = isDocumentHidden ? backgroundTry + 1 : backgroundTry; - if (shouldGiveUp) { - if (isDocumentHidden) { - if (hiddenRetryCount > 10) { - updateTokens(null); - oidc.publishEvent(eventNames.refreshTokensAsync_error, { - message: 'refresh token failed after max hidden retries', - }); - return { tokens: null, status: 'SESSION_LOST' }; - } - return { tokens: oidc.tokens, status: 'GIVE_UP' }; - } else { - updateTokens(null); - oidc.publishEvent(eventNames.refreshTokensAsync_error, { message: 'refresh token' }); - return { tokens: null, status: 'SESSION_LOST' }; - } + if (tryNumber >= maxTries || backgroundTry >= maxBackgroundTries) { + updateTokens(null); + oidc.publishEvent(eventNames.refreshTokensAsync_error, { message: 'refresh token' }); + return { tokens: null, status: 'SESSION_LOST' }; } if (!extras) { @@ -288,18 +279,17 @@ const synchroniseTokensAsync = return { tokens: silent_token_response.tokens, status: 'LOGGED' }; } catch (exceptionSilent: any) { console.error(exceptionSilent); - oidc.publishEvent(eventNames.refreshTokensAsync_silent_error, { message: 'exceptionSilent', exception: exceptionSilent.message, }); return await synchroniseTokensAsync(oidc)( updateTokens, - nextIndex, + nextTry, + nextBackgroundTry, forceRefresh, extras, scope, - nextHiddenRetryCount, ); } }; @@ -346,7 +336,7 @@ const synchroniseTokensAsync = return { tokens: oidc.tokens, status: 'GIVE_UP' }; } - oidc.publishEvent(eventNames.refreshTokensAsync_begin, { tryNumber: index }); + oidc.publishEvent(eventNames.refreshTokensAsync_begin, { tryNumber: tryNumber }); return await localSilentLoginAsync(); default: { if ( @@ -361,8 +351,10 @@ const synchroniseTokensAsync = oidc.publishEvent(eventNames.refreshTokensAsync_begin, { refreshToken: tokens.refreshToken, status, - tryNumber: index, + tryNumber: tryNumber, + backgroundTry: backgroundTry, }); + if (!tokens.refreshToken) { return await localSilentLoginAsync(); } @@ -459,11 +451,11 @@ const synchroniseTokensAsync = return await synchroniseTokensAsync(oidc)( updateTokens, - nextIndex, + nextTry, + nextBackgroundTry, forceRefresh, extras, scope, - nextHiddenRetryCount, ); } }; @@ -484,11 +476,11 @@ const synchroniseTokensAsync = setTimeout(() => { synchroniseTokensAsync(oidc)( updateTokens, - nextIndex, + nextTry, + nextBackgroundTry, forceRefresh, extras, scope, - nextHiddenRetryCount, ) .then(resolve) .catch(reject);