diff --git a/LEARNINGS.md b/LEARNINGS.md index 45ce680..0f72426 100644 --- a/LEARNINGS.md +++ b/LEARNINGS.md @@ -7,6 +7,42 @@ ## Learnings +### 2026-04-03 | Auth | Session expiry redirect — Auth.js v5 + Edge runtime split + +**Problem:** Auth.js `authorize()` callback uses `@node-rs/argon2` (native module, not Edge-compatible). Using `auth()` directly in `middleware.ts` would pull argon2 into the Edge bundle and crash. + +**Solution — split config pattern:** +- `auth.config.ts` — edge-safe subset: `pages`, `session`, `cookies`, no providers, no callbacks that touch DB or argon2 +- `auth-edge.ts` — `NextAuth(authConfig)` with the lean config; used only by middleware +- `auth.ts` — spreads `authConfig`, adds Credentials provider + argon2 callbacks + prisma session tracking + +**Middleware wrapping:** +```ts +import { auth } from "./server/auth-edge.js"; +export default auth(function middleware(request) { + if (!isPublicPath(pathname) && !request.auth) { + return NextResponse.redirect(new URL("/auth/signin", request.url)); + } + // CSP logic... +}); +``` + +**Three-layer defence:** +1. Middleware — server-side redirect before page renders +2. `SessionGuard` client component — `useSession()` → `router.replace()` on SPA navigation +3. `QueryCache` / `MutationCache` in TRPCProvider — UNAUTHORIZED tRPC errors → `window.location.replace()` + +**Test mock pattern for middleware tests:** +```ts +vi.mock("./server/auth-edge.js", () => ({ + auth: (handler) => (req) => + handler(Object.assign(req, { auth: { user: { id: "test-user" } } })), +})); +``` +Needed because `vi.resetModules()` inside the helper function doesn't re-apply top-level mocks — always declare `vi.mock(...)` at file scope. + +--- + ### 2026-04-02 | DevOps | Gitea API token location **Token:** `~/.gitea-token` (chmod 600, never committed to repo)