diff --git a/.changeset/token-cache-iat-core2.md b/.changeset/token-cache-iat-core2.md new file mode 100644 index 00000000000..4d8d2a05f92 --- /dev/null +++ b/.changeset/token-cache-iat-core2.md @@ -0,0 +1,5 @@ +--- +'@clerk/clerk-js': patch +--- + +Fix token cache stale-while-revalidate timing to use the JWT issued-at time, keeping refresh thresholds accurate when tokens are cached after issuance. diff --git a/packages/clerk-js/src/core/__tests__/tokenCache.test.ts b/packages/clerk-js/src/core/__tests__/tokenCache.test.ts index 52e69871800..95f50a41f1e 100644 --- a/packages/clerk-js/src/core/__tests__/tokenCache.test.ts +++ b/packages/clerk-js/src/core/__tests__/tokenCache.test.ts @@ -410,7 +410,7 @@ describe('SessionTokenCache', () => { it('removes token when it expires within the leeway threshold', async () => { const nowSeconds = Math.floor(Date.now() / 1000); - const iat = nowSeconds; + const iat = nowSeconds - 13; const exp = iat + 20; const soonJwt = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.${btoa(JSON.stringify({ iat, exp }))}.signature`; @@ -419,7 +419,7 @@ describe('SessionTokenCache', () => { jwt: { claims: { exp, iat } }, } as any); - SessionTokenCache.set({ createdAt: nowSeconds - 13, tokenId: 'soon_expired_token', tokenResolver }); + SessionTokenCache.set({ createdAt: nowSeconds, tokenId: 'soon_expired_token', tokenResolver }); await tokenResolver; diff --git a/packages/clerk-js/src/core/resources/__tests__/Session.test.ts b/packages/clerk-js/src/core/resources/__tests__/Session.test.ts index 9d0d183525a..f2b279fce59 100644 --- a/packages/clerk-js/src/core/resources/__tests__/Session.test.ts +++ b/packages/clerk-js/src/core/resources/__tests__/Session.test.ts @@ -21,9 +21,9 @@ describe('Session', () => { beforeEach(() => { // Mock Date.now() to make the test tokens appear valid // mockJwt has iat: 1666648250, exp: 1666648310 - // Set current time to 1666648260 (10 seconds after iat, 50 seconds before exp) + // Set current time to iat so token appears freshly issued (60 seconds before exp) vi.useFakeTimers(); - vi.setSystemTime(new Date(1666648260 * 1000)); + vi.setSystemTime(new Date(1666648250 * 1000)); }); afterEach(() => { diff --git a/packages/clerk-js/src/core/tokenCache.ts b/packages/clerk-js/src/core/tokenCache.ts index c95faf79cb5..5c68cf3c4aa 100644 --- a/packages/clerk-js/src/core/tokenCache.ts +++ b/packages/clerk-js/src/core/tokenCache.ts @@ -339,6 +339,7 @@ const MemoryTokenCache = (prefix = KEY_PREFIX): TokenCache => { const issuedAt = claims.iat; const expiresIn: Seconds = expiresAt - issuedAt; + value.createdAt = issuedAt; value.expiresIn = expiresIn; const timeoutId = setTimeout(deleteKey, expiresIn * 1000);