From 51bd7deaaad5e8ceff9f449cd7b818a065e73dbd Mon Sep 17 00:00:00 2001 From: Ridhim Singh Raizada <98144669+Ridhim-RR@users.noreply.github.com> Date: Tue, 4 Nov 2025 05:37:32 +0530 Subject: [PATCH] fix(session): persist additionalFields in cookie cache (#5735) --- .../src/api/routes/session-api.test.ts | 70 +++++++++++++++++++ .../better-auth/src/api/routes/session.ts | 70 ++++++++++++++++--- 2 files changed, 130 insertions(+), 10 deletions(-) diff --git a/packages/better-auth/src/api/routes/session-api.test.ts b/packages/better-auth/src/api/routes/session-api.test.ts index 9fc6c5e3cc..d5f59f1844 100644 --- a/packages/better-auth/src/api/routes/session-api.test.ts +++ b/packages/better-auth/src/api/routes/session-api.test.ts @@ -1342,4 +1342,74 @@ describe("cookie cache versioning", async () => { expect(session.data).not.toBeNull(); expect(session.data?.user.email).toBe(testUser.email); }); + + it("should include additionalFields when retrieving from cookie cache", async () => { + const { client, testUser, cookieSetter, auth } = await getTestInstance({ + session: { + additionalFields: { + role: { + type: "string", + defaultValue: "user", + returned: true, // Should be included + }, + preferences: { + type: "json", + defaultValue: "{}", + returned: true, + }, + }, + cookieCache: { + enabled: true, + strategy: "compact", + }, + }, + }); + + const ctx = await auth.$context; + const fn = vi.spyOn(ctx.adapter, "findOne"); + + const headers = new Headers(); + + // Sign in + await client.signIn.email( + { + email: testUser.email, + password: testUser.password, + }, + { + onSuccess: cookieSetter(headers), + }, + ); + + // First call - should hit database + const firstCall = fn.mock.calls.length; + const session1 = await client.getSession({ + fetchOptions: { + headers, + }, + }); + + expect(session1.data).toBeTruthy(); + expect(session1.data?.session).toHaveProperty("role"); // ? Should have additionalFields + expect(session1.data?.session).toHaveProperty("preferences"); // ? Should have additionalFields + + // Second call - should use cookie cache (no DB call) + const session2 = await client.getSession({ + fetchOptions: { + headers, + }, + }); + + // Verify cache was used (no additional DB calls) + expect(fn.mock.calls.length).toBe(firstCall); + + // ? THIS IS THE KEY TEST - additionalFields should be present from cache + expect(session2.data?.session).toHaveProperty("role"); + expect(session2.data?.session).toHaveProperty("preferences"); + + // Verify values match + const s1 = session1.data?.session as Record; + const s2 = session2.data?.session as Record; + expect(s2.role).toBe(s1.role); + }); }); diff --git a/packages/better-auth/src/api/routes/session.ts b/packages/better-auth/src/api/routes/session.ts index 102d9edfc2..12611a2398 100644 --- a/packages/better-auth/src/api/routes/session.ts +++ b/packages/better-auth/src/api/routes/session.ts @@ -20,6 +20,7 @@ import { } from "../../cookies"; import { getSessionQuerySchema } from "../../cookies/session-store"; import { symmetricDecodeJWT, verifyJWT } from "../../crypto"; +import { parseSessionOutput, parseUserOutput } from "../../db"; import type { InferSession, InferUser, Session, User } from "../../types"; import type { Prettify } from "../../types/helper"; import { getDate } from "../../utils/date"; @@ -269,20 +270,57 @@ export const getSession =