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 fa04e940d7..5753446228 100644 --- a/packages/better-auth/src/api/routes/session-api.test.ts +++ b/packages/better-auth/src/api/routes/session-api.test.ts @@ -19,7 +19,7 @@ describe("session", async () => { const cookies = parseSetCookieHeader(header || ""); expect(cookies.get("better-auth.session_token")).toMatchObject({ value: expect.any(String), - "max-age": (60 * 60 * 24 * 7).toString(), + "max-age": 60 * 60 * 24 * 7, path: "/", httponly: true, samesite: "lax", @@ -141,7 +141,7 @@ describe("session", async () => { const cookies = parseSetCookieHeader(header || ""); expect(cookies.get("better-auth.session_token")).toMatchObject({ value: expect.any(String), - "max-age": (60 * 60 * 24 * 7).toString(), + "max-age": 60 * 60 * 24 * 7, path: "/", httponly: true, samesite: "lax", diff --git a/packages/better-auth/src/cookies/cookie-utils.ts b/packages/better-auth/src/cookies/cookie-utils.ts index ed62699153..52114dbaf8 100644 --- a/packages/better-auth/src/cookies/cookie-utils.ts +++ b/packages/better-auth/src/cookies/cookie-utils.ts @@ -1,6 +1,6 @@ interface CookieAttributes { value: string; - "max-age"?: string; + "max-age"?: number; expires?: Date; domain?: string; path?: string; @@ -34,12 +34,13 @@ export function parseSetCookieHeader( const [attrName, ...attrValueParts] = attribute.split("="); const attrValue = attrValueParts.join("="); - // Normalize the attribute name to camelCase const normalizedAttrName = attrName.trim().toLowerCase(); switch (normalizedAttrName) { case "max-age": - attrObj["max-age"] = attrValue; + attrObj["max-age"] = attrValue + ? parseInt(attrValue.trim(), 10) + : undefined; break; case "expires": attrObj.expires = attrValue ? new Date(attrValue.trim()) : undefined; diff --git a/packages/better-auth/src/integrations/next-js.ts b/packages/better-auth/src/integrations/next-js.ts index f4f7559a49..68ed2f4fe4 100644 --- a/packages/better-auth/src/integrations/next-js.ts +++ b/packages/better-auth/src/integrations/next-js.ts @@ -24,24 +24,23 @@ export const nextCookies = () => { hooks: { after: [ { - matcher() { + matcher(ctx) { return true; }, handler: async (ctx) => { - const returned = ctx.context.endpoint?.headers; + const returned = ctx.responseHeader; if (returned instanceof Headers) { const setCookies = returned?.get("set-cookie"); if (!setCookies) return; const parsed = parseSetCookieHeader(setCookies); const cookieHelper = await cookies(); parsed.forEach((value, key) => { - if (!value) return; if (!key) return; const opts = { - samesite: value.samesite, + sameSite: value.samesite, secure: value.secure, - "max-age": value["max-age"], - httponly: value.httponly, + maxAge: value["max-age"], + httpOnly: value.httponly, domain: value.domain, path: value.path, }; diff --git a/packages/better-auth/src/plugins/multi-session/index.ts b/packages/better-auth/src/plugins/multi-session/index.ts index 1810549222..3e9e9cc62a 100644 --- a/packages/better-auth/src/plugins/multi-session/index.ts +++ b/packages/better-auth/src/plugins/multi-session/index.ts @@ -6,11 +6,13 @@ import { sessionMiddleware, } from "../../api"; import { + deleteSessionCookie, parseCookies, parseSetCookieHeader, setSessionCookie, } from "../../cookies"; import type { BetterAuthPlugin } from "../../types"; +import { returnHookResponse } from "../../utils/plugin-helper"; interface MultiSessionConfig { /** @@ -98,12 +100,7 @@ export const multiSession = (options?: MultiSessionConfig) => { message: "Invalid session id", }); } - await ctx.setSignedCookie( - ctx.context.authCookies.sessionToken.name, - sessionId, - ctx.context.secret, - ctx.context.authCookies.sessionToken.options, - ); + await setSessionCookie(ctx, session); return ctx.json(session); }, ), @@ -139,7 +136,6 @@ export const multiSession = (options?: MultiSessionConfig) => { if (!isActive) return ctx.json({ success: true }); const cookieHeader = ctx.headers?.get("cookie"); - const authCookies = ctx.context.authCookies; if (cookieHeader) { const cookies = Object.fromEntries(parseCookies(cookieHeader)); @@ -165,22 +161,13 @@ export const multiSession = (options?: MultiSessionConfig) => { const nextSession = validSessions[0]; await setSessionCookie(ctx, nextSession); } else { - ctx.setCookie(authCookies.sessionToken.name, "", { - ...authCookies.sessionToken.options, - maxAge: 0, - }); + deleteSessionCookie(ctx); } } else { - ctx.setCookie(authCookies.sessionToken.name, "", { - ...authCookies.sessionToken.options, - maxAge: 0, - }); + deleteSessionCookie(ctx); } } else { - ctx.setCookie(authCookies.sessionToken.name, "", { - ...authCookies.sessionToken.options, - maxAge: 0, - }); + deleteSessionCookie(ctx); } return ctx.json({ success: true, @@ -244,22 +231,27 @@ export const multiSession = (options?: MultiSessionConfig) => { handler: createAuthMiddleware(async (ctx) => { const cookieHeader = ctx.headers?.get("cookie"); if (!cookieHeader) return; - const cookies = Object.fromEntries(parseCookies(cookieHeader)); - - await Promise.all( - Object.entries(cookies).map(async ([key, value]) => { + const ids = Object.keys(cookies) + .map((key) => { if (isMultiSessionCookie(key)) { ctx.setCookie(key, "", { maxAge: 0 }); const id = key.split("_multi-")[1]; - await ctx.context.internalAdapter.deleteSession(id); + return id; } - }), - ); - - return { - responseHeader: ctx.responseHeader, - }; + return null; + }) + .filter((v): v is string => v !== null); + await ctx.context.internalAdapter.deleteSessions(ids); + const response = ctx.context.returned; + if (response instanceof Response) { + console.log("response", ctx.responseHeader.get("set-cookie")); + response.headers.append( + "Set-Cookie", + ctx.responseHeader.get("set-cookie")!, + ); + return { response }; + } }), }, ],