mirror of
https://github.com/better-auth/better-auth.git
synced 2026-05-28 09:56:25 -05:00
fix(session): persist additionalFields in cookie cache (#5735)
This commit is contained in:
committed by
GitHub
parent
82be680ed6
commit
51bd7deaaa
@@ -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<string, any>;
|
||||
const s2 = session2.data?.session as Record<string, any>;
|
||||
expect(s2.role).toBe(s1.role);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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 = <Option extends BetterAuthOptions>() =>
|
||||
// Set the refreshed cookie cache
|
||||
await setCookieCache(ctx, refreshedSession, false);
|
||||
|
||||
ctx.context.session = refreshedSession;
|
||||
// Parse session and user to ensure additionalFields are included
|
||||
// Rehydrate date fields from JSON strings before parsing
|
||||
const parsedRefreshedSession = parseSessionOutput(
|
||||
ctx.context.options,
|
||||
{
|
||||
...refreshedSession.session,
|
||||
expiresAt: new Date(refreshedSession.session.expiresAt),
|
||||
createdAt: new Date(refreshedSession.session.createdAt),
|
||||
updatedAt: new Date(refreshedSession.session.updatedAt),
|
||||
},
|
||||
);
|
||||
const parsedRefreshedUser = parseUserOutput(
|
||||
ctx.context.options,
|
||||
{
|
||||
...refreshedSession.user,
|
||||
createdAt: new Date(refreshedSession.user.createdAt),
|
||||
updatedAt: new Date(refreshedSession.user.updatedAt),
|
||||
},
|
||||
);
|
||||
ctx.context.session = {
|
||||
session: parsedRefreshedSession,
|
||||
user: parsedRefreshedUser,
|
||||
};
|
||||
return ctx.json({
|
||||
session: refreshedSession.session,
|
||||
user: refreshedSession.user,
|
||||
session: parsedRefreshedSession,
|
||||
user: parsedRefreshedUser,
|
||||
} as {
|
||||
session: InferSession<Option>;
|
||||
user: InferUser<Option>;
|
||||
});
|
||||
}
|
||||
|
||||
ctx.context.session = session;
|
||||
// Parse session and user to ensure additionalFields are included
|
||||
const parsedSession = parseSessionOutput(ctx.context.options, {
|
||||
...session.session,
|
||||
expiresAt: new Date(session.session.expiresAt),
|
||||
createdAt: new Date(session.session.createdAt),
|
||||
updatedAt: new Date(session.session.updatedAt),
|
||||
});
|
||||
const parsedUser = parseUserOutput(ctx.context.options, {
|
||||
...session.user,
|
||||
createdAt: new Date(session.user.createdAt),
|
||||
updatedAt: new Date(session.user.updatedAt),
|
||||
});
|
||||
ctx.context.session = {
|
||||
session: parsedSession,
|
||||
user: parsedUser,
|
||||
};
|
||||
return ctx.json({
|
||||
session: session.session,
|
||||
user: session.user,
|
||||
session: parsedSession,
|
||||
user: parsedUser,
|
||||
} as {
|
||||
session: InferSession<Option>;
|
||||
user: InferUser<Option>;
|
||||
@@ -311,9 +349,15 @@ export const getSession = <Option extends BetterAuthOptions>() =>
|
||||
* or if the session refresh is disabled
|
||||
*/
|
||||
if (dontRememberMe || ctx.query?.disableRefresh) {
|
||||
// Parse session and user to ensure additionalFields are included
|
||||
const parsedSession = parseSessionOutput(
|
||||
ctx.context.options,
|
||||
session.session,
|
||||
);
|
||||
const parsedUser = parseUserOutput(ctx.context.options, session.user);
|
||||
return ctx.json({
|
||||
session: session.session,
|
||||
user: session.user,
|
||||
session: parsedSession,
|
||||
user: parsedUser,
|
||||
} as {
|
||||
session: InferSession<Option>;
|
||||
user: InferUser<Option>;
|
||||
@@ -369,9 +413,15 @@ export const getSession = <Option extends BetterAuthOptions>() =>
|
||||
},
|
||||
);
|
||||
|
||||
// Parse session and user to ensure additionalFields are included
|
||||
const parsedUpdatedSession = parseSessionOutput(
|
||||
ctx.context.options,
|
||||
updatedSession,
|
||||
);
|
||||
const parsedUser = parseUserOutput(ctx.context.options, session.user);
|
||||
return ctx.json({
|
||||
session: updatedSession,
|
||||
user: session.user,
|
||||
session: parsedUpdatedSession,
|
||||
user: parsedUser,
|
||||
} as unknown as {
|
||||
session: InferSession<Option>;
|
||||
user: InferUser<Option>;
|
||||
|
||||
Reference in New Issue
Block a user