Skip to content

refactor: forward set-cookie from the signOut response - #107

Merged
mroderick merged 2 commits into
test/cookie-attributesfrom
refactor/logout-as-response
Nov 12, 2026
Merged

mroderick merged 2 commits into
test/cookie-attributesfrom
refactor/logout-as-response

Conversation

@mroderick

@mroderick mroderick commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator

Logout now asks better-auth for the signOut response and appends its Set-Cookie values to the redirect, so no code in this repo decides how cookies are forwarded. forwardCookies and src/app/utils/cookies.js are gone.

const signOut = await auth.api.signOut({
  headers: c.req.raw.headers,
  asResponse: true,
});
if (!signOut.ok) {
  console.error(`Logout failed with status ${signOut.status}`);
  return signOut;
}
const response = c.redirect(callbackURL);
for (const cookie of signOut.headers.getSetCookie()) {
  response.headers.append("Set-Cookie", cookie);
}
return response;

Why this over #103

#103 fixed the symptom: c.header("Set-Cookie", ...) replaces instead of appending, so two of the three clearing cookies vanished. It kept the hand-rolled copy loop and passed { append: true }.

This removes the class of bug instead of fixing an instance of it:

  • Nothing local inspects or rewrites Set-Cookie. The values go from the better-auth Response onto the redirect Response untouched, and Response.headers.append is the transport-level operation rather than a framework context helper with its own semantics.
  • No cookie names appear in the code. signOut decides which cookies to clear; adding or renaming one cannot desynchronise a local list.
  • asResponse: true is better-auth's own API, so the number of cookies is whatever better-auth returns. If a future version clears four, all four arrive.

Why not a better-auth helper

There is none for this direction. better-auth/cookies exports applySetCookies and setCookieToHeader, but both write a request cookie header: applySetCookies ends in target.set("cookie", ...), and inside better-auth the only consumer of setCookieToHeader is the test harness, as cookieSetter. splitSetCookieHeader only splits a comma-joined header. Cookie-name constants do exist (getCookies(auth.options)), but this code needs none.

Equivalence

The #103 tests are unchanged and pass, and the /logout response is byte-identical between the two implementations:

better-auth.session_token=; Max-Age=0; Path=/; HttpOnly; SameSite=Lax
better-auth.session_data=; Max-Age=0; Path=/; HttpOnly; SameSite=Lax
better-auth.dont_remember=; Max-Age=0; Path=/; HttpOnly; SameSite=Lax

One test is added, for the failure path described below.

Review notes

asResponse: true also changes error handling, which is the part worth checking. better-auth throws an APIError when an endpoint fails, but with asResponse it returns an error Response with that status instead (node_modules/better-auth/dist/api/dispatch.mjs:193,249,258). Without a status check, logout would redirect to /?message=Bye! after a failed sign-out while the session still stood. The handler returns the failure instead, and the new test covers it by injecting an auth instance whose signOut answers 500.

Outside error responses the call always resolves to a Response: signOut returned 200 with all three clearing cookies for a valid session, a bogus session token, and no session at all.

Scope: based on test/cookie-attributes, so it carries #103's tests and shows only the mechanism change. Take this one or #103, not both. If this lands, #104's forwardCookies test loses its subject and should be dropped with it.

logout copied Set-Cookie values from a Headers object onto the Hono
context through a hand-rolled helper. Hono's c.header replaces rather
than appends, which is how two of the three clearing cookies were
dropped before #103.

Ask for the signOut response itself with asResponse: true and append its
set-cookie values to the redirect Response. No code in this repo then
decides how cookies are forwarded, so a future handler cannot lose
headers the same way. forwardCookies and its module are gone.
asResponse makes better-auth return APIErrors as error responses
instead of throwing them (dispatch.mjs:193,249,258). logout never read
the status, so a failed signOut redirected to /?message=Bye! while the
session still stood.

Return the signOut response and log the status when it is not ok.
@till

till commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

This is great, @mroderick! :)

@mroderick
mroderick marked this pull request as ready for review November 11, 2026 21:07
@mroderick
mroderick requested a review from till November 11, 2026 21:07
@mroderick
mroderick merged commit 383a024 into test/cookie-attributes Nov 12, 2026
7 checks passed
@mroderick
mroderick deleted the refactor/logout-as-response branch November 12, 2026 07:37
mroderick added a commit that referenced this pull request Nov 12, 2026
/logout answers both verbs from the same handler, but only POST was
covered. Salvaged from #104, whose other two tests targeted code #107
deleted.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants