From 6e6fb7fdd525e064e517c4e5b2a538c1d7b2c286 Mon Sep 17 00:00:00 2001 From: NipuniBhagya Date: Wed, 8 Apr 2026 21:54:20 +0530 Subject: [PATCH] Fix the race condition in token refresh --- .changeset/quick-camels-yell.md | 6 ++++++ .../src/__legacy__/helpers/spa-helper.ts | 21 ++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 .changeset/quick-camels-yell.md diff --git a/.changeset/quick-camels-yell.md b/.changeset/quick-camels-yell.md new file mode 100644 index 00000000..26516379 --- /dev/null +++ b/.changeset/quick-camels-yell.md @@ -0,0 +1,6 @@ +--- +'@asgardeo/browser': patch +'@asgardeo/react': patch +--- + +Fix the race condition in token refresh diff --git a/packages/browser/src/__legacy__/helpers/spa-helper.ts b/packages/browser/src/__legacy__/helpers/spa-helper.ts index 6a2e3157..e4c63e0a 100644 --- a/packages/browser/src/__legacy__/helpers/spa-helper.ts +++ b/packages/browser/src/__legacy__/helpers/spa-helper.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2020-2026, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -24,6 +24,7 @@ import {MainThreadClientConfig, WebWorkerClientConfig} from '../models/client-co export class SPAHelper { private _authenticationClient: AsgardeoAuthClient; private _storageManager: StorageManager; + private _isTokenRefreshLoading: boolean = false; public constructor(authClient: AsgardeoAuthClient) { this._authenticationClient = authClient; @@ -52,12 +53,26 @@ export class SPAHelper const timeUntilRefresh = absoluteExpiryTime - Date.now() - TOKEN_REFRESH_BUFFER_MS; if (timeUntilRefresh <= 0) { - await authenticationHelper.refreshAccessToken(); + if (this._isTokenRefreshLoading) return; + + this._isTokenRefreshLoading = true; + try { + await authenticationHelper.refreshAccessToken(); + } finally { + this._isTokenRefreshLoading = false; + } return; } const timer = setTimeout(async () => { - await authenticationHelper.refreshAccessToken(); + if (this._isTokenRefreshLoading) return; + + this._isTokenRefreshLoading = true; + try { + await authenticationHelper.refreshAccessToken(); + } finally { + this._isTokenRefreshLoading = false; + } }, timeUntilRefresh); await this._storageManager.setTemporaryDataParameter(