fix(desktop): persist auth cookies with max age

This commit is contained in:
DIYgod 2026-05-12 16:12:34 +08:00
parent 425e8610a3
commit 98fcb71734
2 changed files with 66 additions and 2 deletions

View File

@ -1,5 +1,5 @@
import type { Session } from "electron"
import { describe, expect, it, vi } from "vitest"
import { beforeEach, describe, expect, it, vi } from "vitest"
import {
buildManagedAuthCookieHeader,
@ -10,6 +10,10 @@ import {
} from "./auth-cookies"
describe("auth cookies", () => {
beforeEach(() => {
vi.useRealTimers()
})
it("builds a cookie header from managed auth cookies only", () => {
const header = buildManagedAuthCookieHeader([
{ name: "__Secure-better-auth.session_token", value: "session-token" },
@ -104,6 +108,53 @@ describe("auth cookies", () => {
expect(remove).not.toHaveBeenCalled()
})
it("persists session token cookies across app restarts when the server sends Max-Age", async () => {
vi.useFakeTimers()
vi.setSystemTime(new Date("2026-05-12T00:00:00.000Z"))
const set = vi.fn().mockImplementation(async () => {})
const remove = vi.fn().mockImplementation(async () => {})
const get = vi.fn().mockResolvedValue([])
await persistManagedAuthCookiesFromSetCookieHeader({
apiURL: "https://api.folo.is",
session: {
cookies: { get, set, remove },
} as unknown as Session,
setCookieHeader:
"__Secure-better-auth.session_token=session-token; Max-Age=2592000; Path=/; HttpOnly; Secure; SameSite=None",
})
expect(set).toHaveBeenCalledWith(
expect.objectContaining({
name: "__Secure-better-auth.session_token",
value: "session-token",
expirationDate: 1_781_136_000,
}),
)
})
it("keeps rememberMe=false session token cookies session-scoped", async () => {
const set = vi.fn().mockImplementation(async () => {})
const remove = vi.fn().mockImplementation(async () => {})
const get = vi.fn().mockResolvedValue([])
await persistManagedAuthCookiesFromSetCookieHeader({
apiURL: "https://api.folo.is",
session: {
cookies: { get, set, remove },
} as unknown as Session,
setCookieHeader:
"__Secure-better-auth.session_token=session-token; Path=/; HttpOnly; Secure; SameSite=None",
})
expect(set).toHaveBeenCalledWith(
expect.not.objectContaining({
expirationDate: expect.any(Number),
}),
)
})
it("removes stale duplicate session token cookies while keeping the secure host-only cookie", async () => {
const remove = vi.fn().mockImplementation(async () => {})
const get = vi.fn().mockResolvedValue([

View File

@ -224,6 +224,18 @@ const shouldRemoveCookie = (cookie: ParsedSetCookie) => {
return false
}
const getCookieExpirationDate = (cookie: ParsedSetCookie) => {
if (cookie.expirationDate !== undefined) {
return cookie.expirationDate
}
if (cookie.maxAge !== undefined && cookie.maxAge > 0) {
return Math.floor(Date.now() / 1000) + cookie.maxAge
}
return
}
export const getManagedAuthCookieNames = () => {
return [...MANAGED_AUTH_COOKIE_NAMES]
}
@ -368,6 +380,7 @@ export const persistManagedAuthCookiesFromSetCookieHeader = async ({
continue
}
const expirationDate = getCookieExpirationDate(cookie)
const details: CookiesSetDetails = {
url: apiURL,
name: cookie.name,
@ -377,7 +390,7 @@ export const persistManagedAuthCookiesFromSetCookieHeader = async ({
secure: cookie.secure,
...(cookie.sameSite ? { sameSite: cookie.sameSite } : {}),
...(cookie.domain ? { domain: cookie.domain } : {}),
...(cookie.expirationDate ? { expirationDate: cookie.expirationDate } : {}),
...(expirationDate ? { expirationDate } : {}),
}
await session.cookies.set(details)