From 5af531a06b9bad71207886790ebe656f668943dd Mon Sep 17 00:00:00 2001 From: Yohta Kimura <38206553+rajyan@users.noreply.github.com> Date: Sun, 14 Dec 2025 15:57:21 +0900 Subject: [PATCH] fix: update transaction cookie deletion to clear all cookies on successful callback --- src/server/auth-client.ts | 4 ++-- .../redundant-txn-cookie-deletion.test.ts | 23 ++++++++++--------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/server/auth-client.ts b/src/server/auth-client.ts index 8e6c3d534..34ba35f70 100644 --- a/src/server/auth-client.ts +++ b/src/server/auth-client.ts @@ -886,8 +886,8 @@ export class AuthClient { await this.sessionStore.set(req.cookies, res.cookies, session, true); addCacheControlHeadersForSession(res); - // Clean up the current transaction cookie after successful authentication - await this.transactionStore.delete(res.cookies, state); + // Clean up all transaction cookies after successful authentication + await this.transactionStore.deleteAll(req.cookies, res.cookies); return res; } diff --git a/src/server/redundant-txn-cookie-deletion.test.ts b/src/server/redundant-txn-cookie-deletion.test.ts index d7de1d65e..48a26463c 100644 --- a/src/server/redundant-txn-cookie-deletion.test.ts +++ b/src/server/redundant-txn-cookie-deletion.test.ts @@ -447,16 +447,14 @@ describe("Ensure that redundant transaction cookies are deleted from auth-client } as any); }); - it("should delete the correct transaction cookie on success", async () => { + it("should delete all transaction cookies on success", async () => { /** - * Test Purpose: Verify that when OAuth callback succeeds, only the specific transaction - * cookie for that authentication flow is deleted, not all transaction cookies. + * Test Purpose: Verify that when OAuth callback succeeds, all transaction cookies + * are deleted to prevent cookie accumulation. * * Why this matters: * - In successful auth flows, we should clean up the used transaction cookie - * - But preserve other parallel authentication attempts that might be in progress - * - This is the "happy path" that demonstrates proper transaction cookie lifecycle - * - Validates that the state parameter correctly identifies which transaction to clean up + * - By calling deleteAll on successful callback, we clear all accumulated cookies */ // Arrange: First, do a login to get proper state and transaction cookie @@ -471,15 +469,17 @@ describe("Ensure that redundant transaction cookies are deleted from auth-client const txnCookie = loginRes.cookies.get(`__txn_${state}`); expect(txnCookie).toBeDefined(); - // Now create the callback request + // Now create the callback request with multiple transaction cookies const req = new NextRequest( `http://localhost:3000/api/auth/callback?code=auth_code&state=${state}` ); - // Add the transaction cookie to the callback request + // Add the current transaction cookie and some stale ones if (txnCookie) { req.cookies.set(`__txn_${state}`, txnCookie.value); } + req.cookies.set("__txn_old_state_1", "old_value_1"); + req.cookies.set("__txn_old_state_2", "old_value_2"); // Act: Process the successful callback const res = await authClient.handleCallback(req); @@ -490,17 +490,18 @@ describe("Ensure that redundant transaction cookies are deleted from auth-client state ); - // Check that the specific transaction cookie was deleted + // Check that all transaction cookies were deleted const deletedTxnCookies = res.cookies .getAll() .filter( (cookie) => - cookie.name === `__txn_${state}` && + cookie.name.startsWith("__txn_") && cookie.value === "" && cookie.maxAge === 0 ); - expect(deletedTxnCookies.length).toBe(1); + // All 3 transaction cookies should be deleted + expect(deletedTxnCookies.length).toBe(3); expect(mockSessionStoreInstance.set).toHaveBeenCalledTimes(1); expect(res.status).toBeGreaterThanOrEqual(300); expect(res.status).toBeLessThan(400);