Skip to content

fix(auth): a session the API refuses ends at /login, not at a default shell (QA sweep ONB-04) - #32

Merged
NCHILLC merged 1 commit into
mainfrom
fix/qa-onb-04-stale-session
Oct 13, 2026
Merged

NCHILLC merged 1 commit into
mainfrom
fix/qa-onb-04-stale-session

Conversation

@NCHILLC

@NCHILLC NCHILLC commented Oct 13, 2026

Copy link
Copy Markdown
Owner

What

QA sweep finding ONB-04 (Major). A session issued before a password change or reset loaded the workspace shell at HTTP 200 as "Unnamed" on openinspection.dev, with no Dispatch item, on every reload.

Why

The token's exp is still live, so requireToken lets it through, but the API refuses it (pwchanged:{userId}). The loader in app/routes/auth-layout.tsx swallowed that 401 from the session-context call as a "graceful fallback" and rendered default branding.

Change

  • The layout loader ends the session on a 401 from the session-context call (destroyUserSession: both cookies cleared, 302 to /login), the same place a visitor with no cookie lands.
  • Only 401 does this. A 5xx or a thrown fetch still keeps the defaults, since the token may be fine.
  • docs/develop/fork-log.md: new row, and the NET-06 ceiling about a password-changed token bounced to returnTo is amended.

Upstream

No fix there: git fetch upstream plus keyword and file greps (stale session, pwchanged, password reset, auth-boundary files) found only the TOTP and invite-link fixes. Fork deviation, recorded in the fork log.

Tests

  • app/routes/auth-layout.loader.test.ts (4 cases); the 401 case fails against the unfixed loader.
  • tests/e2e/auth-password-reset.spec.ts: keeps a session from before the reset and expects 302 to /login for it, with the fresh session as the control. Not run locally (no Chromium); it runs in the e2e legs.
  • lint:gates 27 of 27, eslint 0 errors, pre-commit and pre-push passed.

Known ceilings

  • Only a document load runs the layout loader, so client-side navigation between child routes on a stale session still shows each child's own fallback until the next full load.
  • returnTo is not carried, and /login shows no "password changed" notice (it would need a message in both catalogs).

🤖 Generated with Claude Code

… shell (QA sweep ONB-04)

A token issued before a password change or reset still has a live `exp`, so
`requireToken` lets it through, but the API refuses it (`pwchanged:{userId}`).
The auth layout loader swallowed that 401 as a "graceful fallback" and the page
came back 200 as an "Unnamed" shell on openinspection.dev with no Dispatch item,
on every reload.

The loader now ends the session on a 401 from the session-context call
(`destroyUserSession`: both cookies cleared, 302 to `/login`), the same place a
visitor with no cookie lands. Only 401 does this; a 5xx or a thrown fetch keeps
the defaults, since the token may be fine.

Tests: `auth-layout.loader.test.ts` (red against the unfixed loader), and the
password-reset e2e now keeps the pre-reset session and expects 302 to `/login`
for it, with the fresh session as the control. fork-log row added; the NET-06
ceiling about a password-changed token bounced to `returnTo` is amended.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@NCHILLC
NCHILLC merged commit b409cee into main Oct 13, 2026
25 checks passed
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.

1 participant