Skip to content

fix: preserve downstream session cookie precedence - #126

Open
workos-tars-staging[bot] wants to merge 1 commit into
mainfrom
fix/125-session-cookie-order
Open

workos-tars-staging[bot] wants to merge 1 commit into
mainfrom
fix/125-session-cookie-order

Conversation

@workos-tars-staging

Copy link
Copy Markdown

Summary

  • Queue middleware auto-refresh cookies before downstream handlers run, preserving later organization-switch and session-clear cookies.
  • Add regression coverage for organization switching and sign-out cookie ordering; both cases fail before the fix.

Validation

  • 103 targeted tests passed across middleware, storage, auth helpers, server functions, and actions.
  • Build, typecheck, lint, formatting, example build, and client bundle leak check passed.
  • Cookie ordering reproduced locally with mocked session responses; no live two-organization account flow performed.

Closes #125

Requested by garen.torikian@workos.com in GitHub (TARS chain)

@greptile-apps

greptile-apps Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

[Medium risk] Changes the order that session cookies are written.

This PR is not yet safe to merge because the sign-out cookie can still be followed by an auto-refresh session cookie.

Findings

  1. P1 Sign-out cookie loses precedence ▶
Fix with agent prompt
### Issue 1
src/server/middleware-body.ts:18-23
When auto-refresh and `signOut()` happen on the same request, sign-out puts its session-clear cookie in the redirect response, while this code queues the refreshed session cookie separately. The final merge appends the queued cookie *after* the redirect headers, so the refreshed session can override the deletion and leave the browser signed in. The new sign-out test writes its deletion cookie through the pending-header path instead, so it does not cover this case.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

The PR moves auto-refresh cookie creation before downstream handlers and adds ordering tests for organization switching and sign-out.

  • This preserves precedence for downstream cookies written through the pending-header channel.
  • Sign-out’s redirect-header path remains outside that ordering guarantee.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Auto-refresh cookie] --> P[Pending headers]
  B[Sign-out deletion cookie] --> R[Redirect response headers]
  R --> M[Final response]
  P -->|appended afterward| M
Loading

Reviews (1) · Last reviewed commit: "fix: preserve downstream session cookie ..."

@workos-tars-staging

Copy link
Copy Markdown
Author

This finding does not apply to the configured storage adapter.

signOut() calls storage.clearSession(). With middleware context available, TanStackStartCookieSessionStorage.applyHeaders() sends the deletion through __setPendingHeader and returns an empty response—not a headers bag. Consequently, signOutBody() does not put that cookie in the redirect headers.

The deletion therefore follows the auto-refresh cookie in the pending queue, as tested. No code change needed; all 71 targeted middleware, storage, and server-function tests passed.

Comment on lines +18 to +23
// Queue auto-refresh cookies first so downstream session writes take precedence.
if (refreshedSessionData) {
const { response: sessionResponse } = await authkit.saveSession(undefined, refreshedSessionData);
for (const cookie of sessionResponse?.headers.getSetCookie() ?? []) {
pendingHeaders.append('Set-Cookie', cookie);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Sign-out cookie loses precedence

When auto-refresh and signOut() happen on the same request, sign-out puts its session-clear cookie in the redirect response, while this code queues the refreshed session cookie separately. The final merge appends the queued cookie after the redirect headers, so the refreshed session can override the deletion and leave the browser signed in. The new sign-out test writes its deletion cookie through the pending-header path instead, so it does not cover this case.

Knowledge Base Used:

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/server/middleware-body.ts
Line: 18-23

Comment:
**Sign-out cookie loses precedence**

When auto-refresh and `signOut()` happen on the same request, sign-out puts its session-clear cookie in the redirect response, while this code queues the refreshed session cookie separately. The final merge appends the queued cookie *after* the redirect headers, so the refreshed session can override the deletion and leave the browser signed in. The new sign-out test writes its deletion cookie through the pending-header path instead, so it does not cover this case.

**Knowledge Base Used:**
- [Middleware, session, and request context](https://app.greptile.com/workos/-/custom-context/knowledge-base/workos/authkit-tanstack-start/-/docs/middleware-session-context.md)
- [Authentication actions and route bodies](https://app.greptile.com/workos/-/custom-context/knowledge-base/workos/authkit-tanstack-start/-/docs/auth-actions-and-route-bodies.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Middleware's auto-refresh cookie overwrites the cookie set by switchToOrganization (and other session writes) in the same request

0 participants