From fabf67f65e097b98ceb5a0c94bf9c6bbe528ca44 Mon Sep 17 00:00:00 2001 From: Mark Wylde Date: Fri, 12 Jun 2026 21:29:51 +0100 Subject: [PATCH] fix(client): prefer localStorage token over memory in token mode --- packages/darkauth-client/src/index.ts | 4 +- .../tests/refreshSession.test.js | 42 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/packages/darkauth-client/src/index.ts b/packages/darkauth-client/src/index.ts index c6bf30d..dbf2307 100644 --- a/packages/darkauth-client/src/index.ts +++ b/packages/darkauth-client/src/index.ts @@ -700,7 +700,9 @@ export async function refreshSession( const currentRefreshMode = refreshMode(); const refreshToken = currentRefreshMode === "token" - ? memoryRefreshToken || localStorage.getItem(REFRESH_TOKEN_KEY) + ? tokenStorageMode() === "localStorage" + ? localStorage.getItem(REFRESH_TOKEN_KEY) || memoryRefreshToken + : memoryRefreshToken || localStorage.getItem(REFRESH_TOKEN_KEY) : null; if (currentRefreshMode === "token" && !refreshToken) return null; const endpoints = await resolveEndpoints(); diff --git a/packages/darkauth-client/tests/refreshSession.test.js b/packages/darkauth-client/tests/refreshSession.test.js index 54d846c..5f1e66d 100644 --- a/packages/darkauth-client/tests/refreshSession.test.js +++ b/packages/darkauth-client/tests/refreshSession.test.js @@ -121,3 +121,45 @@ test("refreshSession force refreshes even when stored id token is still valid", assert.equal(refreshed.idToken, refreshedToken); assert.equal(globalThis.localStorage.getItem("refresh_token"), "rt-6"); }); + +test("refreshSession prefers the latest localStorage refresh token over stale memory in token mode", async () => { + setupEnvironment({ tokenStorage: "localStorage" }); + const firstToken = createIdToken("user-1"); + const secondToken = createIdToken("user-2"); + globalThis.localStorage.setItem("refresh_token", "rt-memory"); + let fetchCalls = 0; + globalThis.fetch = async (_url, init) => { + fetchCalls += 1; + if (fetchCalls === 1) { + assert.equal(init.body.get("refresh_token"), "rt-memory"); + return { + ok: true, + status: 200, + json: async () => ({ + id_token: firstToken, + access_token: "at-1", + refresh_token: "rt-memory-next", + }), + }; + } + + assert.equal(init.body.get("refresh_token"), "rt-other-tab"); + return { + ok: true, + status: 200, + json: async () => ({ + id_token: secondToken, + access_token: "at-2", + refresh_token: "rt-final", + }), + }; + }; + + await refreshSession({ force: true }); + globalThis.localStorage.setItem("refresh_token", "rt-other-tab"); + const refreshed = await refreshSession({ force: true }); + + assert.equal(fetchCalls, 2); + assert.equal(refreshed.idToken, secondToken); + assert.equal(globalThis.localStorage.getItem("refresh_token"), "rt-final"); +});