Two cleanups in one pass: 1. Update import paths app-wide from `~/lib/auth.server` to `~/lib/auth/session.server` for the four session helpers (sessionStorage, createSession, getSessionUser, destroySession). ~40 files: 33 simple path swaps where the file imported only session symbols, 5 splits where it also imported per-method auth functions (auth.verify.tsx, api.settings.email.ts, activities.\$id.tsx, routes.\$id.tsx, auth.accept-terms.tsx) — those keep one import from auth.server (for verifyMagicToken, canView, recordTermsAcceptance, etc.) and gain a second import from auth/session.server. Two more files used relative paths and were missed by the first grep pass (lib/oauth.server.ts and routes/oauth.authorize.tsx) — migrated too. The @deprecated re-exports block in auth.server.ts is gone. 2. Rename the new auth files to follow the project's `.server.ts` convention so Vite/React Router treat them as server-only (they read process.env.SESSION_SECRET, hit the DB, etc. — must NOT enter the client bundle): - auth/session.ts → auth/session.server.ts - auth/completion.ts → auth/completion.server.ts - auth/completion.test.ts → auth/completion.server.test.ts Done with `git mv` so blame is preserved. Verified: typecheck + lint green; 126 unit tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 KiB
3 KiB
1. New auth module structure
- 1.1 Create
apps/journal/app/lib/auth/directory. - 1.2 Create
apps/journal/app/lib/auth/session.tsand movesessionStorage,createSession,getSessionUser,destroySessionfromauth.server.ts(preserve behaviour, includingprocess.env.SESSION_SECRETsource). - 1.3 In
auth.server.ts, re-export the moved helpers from./auth/session.tsso existing imports keep working unchanged. Add a JSDoc@deprecated-style comment pointing at the new path.
2. completeAuth chokepoint
- 2.1 Write
apps/journal/app/lib/auth/completion.test.ts(TDD red): scenarios for returnTo defaults to/, returnTo//evil.comrejected, returnTohttps://evil.comrejected, response is a 302/303 redirect, response includes Set-Cookie naming__session. - 2.2 Create
apps/journal/app/lib/auth/completion.tsexportingcompleteAuth({ userId, request, returnTo? }) → Promise<Response>and a privatesafeReturnTo(value)helper. Implementation:createSession(userId, request);redirect(safeReturnTo(returnTo) ?? "/", { headers: { "Set-Cookie": cookie } }). Terms recording is not here — both registration paths already record terms at user creation, so the chokepoint is purely session + redirect. - 2.3 Run completion tests green.
3. Caller migration
- 3.1
apps/journal/app/routes/api.auth.register.tspasskey-finish branch — replace inlined session+redirect withreturn completeAuth({ userId, request, returnTo }). Drop now-unused imports. - 3.2
apps/journal/app/routes/api.auth.login.tspasskeystep: "finish-passkey"branch — replace withreturn completeAuth({ userId, request, returnTo }). - 3.3
apps/journal/app/routes/api.auth.login.tsmagic-linkstep: "verify-code"branch — replace withreturn completeAuth(...). - 3.4
apps/journal/app/routes/auth.verify.tsxmagic-link click-through consumer — replace withreturn completeAuth(...). - 3.5 Confirm no other callers of
createSessionremain inside auth route handlers (they should all flow throughcompleteAuth).getSessionUseranddestroySessioncontinue to be called directly from non-completion sites — that's expected.
4. Verification
- 4.1
pnpm typecheck && pnpm lint && pnpm testgreen. - 4.2
pnpm test:e2e(auth flows) green without modification — proves behaviour-preserving refactor. - 4.3 Manual sanity: register with passkey locally, login with passkey, log out, re-login via magic-link 6-digit code, click-through magic link from
auth.verify.tsx. Confirm session cookie set + correct redirect each time. Verified 2026-05-08 over plain HTTP (HTTPS dev hits a pre-existing HTTP/2 + missing-Host issue with React Router 7.14's CSRF check — separate follow-up).
5. Documentation + follow-up
- 5.1 At archive time, apply the spec delta in
specs/authentication-methods/toopenspec/specs/. - 5.2 Update import paths app-wide from
auth.server.tsto./auth/session.tsand drop the re-exports. (Folded into this PR after the smoke test confirmed everything works.)