From 75539c7b4b1a046068dbf6e09d47021e330e20b1 Mon Sep 17 00:00:00 2001 From: Kostas Pyliouras Date: Thu, 27 Aug 2026 18:03:14 +0200 Subject: [PATCH 1/2] fix session-token recovery and refresh error handling in SessionService --- .../web-core/src/services/SessionService.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/web-core/src/services/SessionService.ts b/packages/web-core/src/services/SessionService.ts index 9e60a4c0b..6e79159d6 100644 --- a/packages/web-core/src/services/SessionService.ts +++ b/packages/web-core/src/services/SessionService.ts @@ -21,6 +21,7 @@ import { AuthState, base64decode, CorbadoError, + NonRecoverableError, PasskeyAlreadyExistsError, type PasskeyDeleteError, PasskeysNotSupported, @@ -100,17 +101,18 @@ export class SessionService { this.#sessionConfig = sessionConfig.val; this.#refreshToken = SessionService.#getRefreshToken(); this.#sessionToken = SessionService.#getSessionToken(); + this.#setApisV2(this.#refreshToken); // if the session is valid, we emit it if (this.#sessionToken && this.#sessionToken.isValidForXMoreSeconds(0)) { log.debug('emit session-token', this.#sessionToken); this.#onSessionTokenChange(this.#sessionToken); } else { - await this.#handleRefreshRequest(); + // the session-token cookie may have expired while a valid refresh session still exists + // (HTTP-only cookie) => attempt one recovery refresh, the server decides + await this.#refresh(); } - this.#setApisV2(this.#refreshToken); - // init scheduled session refresh this.#refreshIntervalId = setInterval(() => { void this.#handleRefreshRequest(); @@ -456,9 +458,14 @@ export class SessionService { this.setSession(response.data.sessionToken, undefined); } catch (e) { - // if it's a network error, we should do a retry - // for all other errors, we should log out the user log.warn(e); + + // transient network failure (e.g. wake from sleep before the network is back up): + // keep the session, the scheduled refresh retries => log out only on real backend rejections + if (!navigator.onLine || (e instanceof NonRecoverableError && e.message.includes('no_data_in_response'))) { + return; + } + await this.logout(); } } From 769a9450bfeaae0ae085750f4e9f598e0c95d250 Mon Sep 17 00:00:00 2001 From: Kostas Pyliouras Date: Thu, 27 Aug 2026 18:50:51 +0200 Subject: [PATCH 2/2] keep stored refresh-token on API client after session refresh --- packages/web-core/src/services/SessionService.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/web-core/src/services/SessionService.ts b/packages/web-core/src/services/SessionService.ts index 6e79159d6..9118f9300 100644 --- a/packages/web-core/src/services/SessionService.ts +++ b/packages/web-core/src/services/SessionService.ts @@ -257,7 +257,8 @@ export class SessionService { const sessionTokenModel = new SessionToken(sessionToken); this.#setSessionToken(sessionTokenModel); - this.#setApisV2(refreshToken ?? ''); + // a refresh response carries no new refresh-token => keep the stored one (payload mode has no cookie fallback) + this.#setApisV2(refreshToken ?? this.#refreshToken ?? ''); this.#onSessionTokenChange(sessionTokenModel); this.#setRefreshToken(refreshToken);