Strategic shift. Decided to migrate auth from the rolled-their-own JWT system to Auth.js v5 with Google OAuth + Credentials providers, rather than continuing to patch the existing system in place. Launch slipped from W21 to W23+ (~2 weeks). Full rationale in [[Projects/personal-finance-notion/decisions/adr-2026-05-18-authjs-migration|ADR 2026-05-18]].
Day-1 audit fixes landed in working tree (commits pending):
"Internal server error"; 4xx detail preserved for validation UX. logger.error replaces console.error. (src/lib/apiHelper.ts:42-44, 86-107)src/lib/auth.ts:345-353)api-reads StaleWhileRevalidate cache for /api/* GETs replaced with NetworkOnly. Closes the shared-device cross-user JSON leak. (next.config.mjs:25-35)"Email already exists" masked to a generic message. Full enumeration-safe signup ships in migration Phase B. (src/lib/actions/user.ts:123-132)The 2026-05-17 [[Projects/personal-finance-notion/context/audit-2026-05-17-auth|auth audit]] found that password reset (C1) and email verification (C2) — both required for launch — would need 4–5 days of custom work (email infra + token models + flows). Given that effort was unavoidable, folding it into a full Auth.js migration buys Google OAuth + CSRF/cookie defaults + reduced maintenance surface for ~5 extra days. Honest trade: Auth.js does not ship password reset or email verify for Credentials — those still need to be custom-built on top.
| Audit item | Status after 2026-05-18 |
|---|---|
| C1 Password reset | Done — [[Projects/personal-finance-notion/backlog/done/p0-c1-password-reset|C1]] |
| C2 Email verification | Superseded — Phase B |
| C3 Signup enumeration | Partial mask landed; full fix Phase B |
| C4 API error leakage | Done (commit pending) |
| H1 CSP | Phase C |
| H2 Login timing | Phase C |
| H3 Blacklist race | Done (commit pending); moot under Auth.js |
| H4 PWA cache leak | Done (commit pending) |
| M1 Legacy cookie reads | Superseded by Auth.js |
| M2 Role field | Phase C decision |
| M3 Dual JWT secrets | Superseded by Auth.js (single AUTH_SECRET) |
| M4 CSRF posture | Improved by Auth.js defaults |
| M5 Logger stringifier | Phase C |
| L1 Integration API tokens | Elevated to Phase C (blocking re-enable) |
| L2–L7 | Backlog unchanged |
userId vs. write thin adapter).