trails/openspec/changes/unify-auth-completion/tasks.md
Ullrich Schäfer b9aac2859a
Drop auth.server.ts re-exports + rename to .server.ts convention (task 5.2)
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>
2026-05-08 03:01:30 +02:00

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.ts and move sessionStorage, createSession, getSessionUser, destroySession from auth.server.ts (preserve behaviour, including process.env.SESSION_SECRET source).
  • 1.3 In auth.server.ts, re-export the moved helpers from ./auth/session.ts so 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.com rejected, returnTo https://evil.com rejected, response is a 302/303 redirect, response includes Set-Cookie naming __session.
  • 2.2 Create apps/journal/app/lib/auth/completion.ts exporting completeAuth({ userId, request, returnTo? }) → Promise<Response> and a private safeReturnTo(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.ts passkey-finish branch — replace inlined session+redirect with return completeAuth({ userId, request, returnTo }). Drop now-unused imports.
  • 3.2 apps/journal/app/routes/api.auth.login.ts passkey step: "finish-passkey" branch — replace with return completeAuth({ userId, request, returnTo }).
  • 3.3 apps/journal/app/routes/api.auth.login.ts magic-link step: "verify-code" branch — replace with return completeAuth(...).
  • 3.4 apps/journal/app/routes/auth.verify.tsx magic-link click-through consumer — replace with return completeAuth(...).
  • 3.5 Confirm no other callers of createSession remain inside auth route handlers (they should all flow through completeAuth). getSessionUser and destroySession continue to be called directly from non-completion sites — that's expected.

4. Verification

  • 4.1 pnpm typecheck && pnpm lint && pnpm test green.
  • 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/ to openspec/specs/.
  • 5.2 Update import paths app-wide from auth.server.ts to ./auth/session.ts and drop the re-exports. (Folded into this PR after the smoke test confirmed everything works.)