Phase 2: Auth.js v5 cutover, replace Supabase Auth
Frontend authentication switches from Supabase Auth to Auth.js v5
with a Credentials provider. The Supabase Auth code paths are fully
removed. The Supabase JS client is no longer present in the frontend
bundle. Microsoft Entra OIDC will be added as a second provider in
the next sub-phase.
Session model:
- Session JWT is HS256-signed with AUTH_SECRET, stored in an httpOnly
cookie set by Auth.js. The browser cannot read it.
- For backend API calls the browser obtains a short-lived (5 minute)
HS256 JWT from GET /api/session-token. The Next.js server mints it
from the verified Auth.js session, signed with the same AUTH_SECRET.
- The backend requireAuth middleware verifies any bearer HS256 JWT
with the shared AUTH_SECRET. No Supabase Auth lookup is performed.
Backend changes:
- New routes/auth.ts: POST /register, POST /verify-credentials, GET /me.
- New lib/users.ts: centralised user creation, sign-in verification,
email-domain allowlist enforcement, bootstrap-admin promotion.
- New lib/passwords.ts: bcryptjs at cost 12, min length 12.
- New lib/authToken.ts: jose-based HS256 verify/sign.
- middleware/auth.ts rewritten to verify Auth.js JWT. New
requireAdmin middleware checks res.locals.userRole.
- BOOTSTRAP_ADMIN_EMAIL env grants admin role on boot and on first
matching registration.
- /ready endpoint pings Postgres before reporting ready.
- Sign-in responses are deliberately indistinguishable between
"no such user" and "wrong password" to prevent user enumeration.
Frontend changes:
- New auth.ts wires NextAuth Credentials provider with custom HS256
encode/decode.
- /api/auth/[...nextauth]/route.ts exposes Auth.js handlers.
- /api/session-token mints short-lived backend bearers.
- middleware.ts redirects unauthenticated requests to /login for any
path outside the public allowlist.
- AuthContext.tsx is now a thin shim around useSession; the existing
useAuth() API is preserved so 30+ call sites keep working unchanged.
- providers.tsx wraps the tree in SessionProvider.
- login and signup pages rewritten for the new flow. Signup calls
POST /auth/register then signIn("credentials"). Password minimum
bumped to 12.
- mikeApi.ts and seven other files migrated to a shared
getSessionToken() helper. None of them call Supabase directly.
- Deleted dead frontend/src/lib/{auth,supabase}.ts.
- Uninstalled @supabase/supabase-js, @supabase/auth-helpers-nextjs,
@supabase/auth-js from the frontend.
Docs:
- docs/developer/07-auth.md documents the new flow end to end with
a sequence diagram.
- docs/security/03-encryption.md records every cryptographic primitive
and rotation procedure.
- Instructions decisions log and CHANGELOG updated.
Note: backend routes that still use the Supabase JS client for
PostgREST data queries are unchanged in this commit. The Supabase JS
client is retained on the backend as a transitional dependency.
Migration onto plain pg is the next sub-phase.
| Repository | cpatpa/PIP |
|---|---|
| Author | Claude <noreply@anthropic.com> |
| Authored | |
| Parents | 76691b24 |
| Stats | 35 files changed , +1375 , -465 |
| Part of | Phase 2 - Auth.js v5 + Entra OIDC + password reset |
Capture this commit into my fork
Download a Markdown prompt that tells Claude how to port this
exact commit into your working tree. Run it via
claude -p < capture-commit-b4f7697f.md
from inside the repo you want the change in.