71 lines
2.8 KiB
Markdown
71 lines
2.8 KiB
Markdown
---
|
|
status: accepted
|
|
date: 2026-05-03
|
|
decision-makers: [janpetervisser]
|
|
---
|
|
|
|
# ADR-0005: Use iron-session for authentication instead of NextAuth/Clerk/Supabase Auth
|
|
|
|
## Context and Problem Statement
|
|
|
|
Scrum4Me requires username/password login without email verification, a synchronous demo-user check on every request, and full control over the session cookie shape (including an `isDemo` flag). Which authentication solution fits these constraints at minimal complexity?
|
|
|
|
## Decision Drivers
|
|
|
|
- No email required — username/password only.
|
|
- Demo-user policy (ADR-0006) requires a synchronous `isDemo` check in both middleware and server actions.
|
|
- No third-party redirect chain — auth must stay in-process.
|
|
- Solo-developer project: minimal external dependencies preferred.
|
|
|
|
## Considered Options
|
|
|
|
- **NextAuth / Auth.js v5**
|
|
- **Clerk**
|
|
- **Supabase Auth**
|
|
- **iron-session + bcryptjs**
|
|
|
|
## Decision Outcome
|
|
|
|
Chosen option: **iron-session + bcryptjs**, because it is the only option that gives us full control over cookie contents, has zero external redirect dependency, and lets us embed `isDemo` directly in the session payload.
|
|
|
|
### Consequences
|
|
|
|
- Good, because session structure is fully controlled — we add any field we need.
|
|
- Good, because no external service dependency for auth; works offline and in CI.
|
|
- Good, because synchronous cookie read in `proxy.ts` middleware is trivial.
|
|
- Bad, because we own the password hashing, session rotation, and CSRF protection.
|
|
- Bad, because no OAuth/social login without building it ourselves.
|
|
|
|
### Confirmation
|
|
|
|
`lib/session.ts` defines the session type. `docs/patterns/iron-session.md` documents the pattern. Any new field on the session object must be added to the type there.
|
|
|
|
## Pros and Cons of the Options
|
|
|
|
### NextAuth / Auth.js v5
|
|
|
|
- Good, because OAuth, email magic links, and credentials all in one library.
|
|
- Bad, because credentials provider is discouraged in v5; session shape is opaque.
|
|
- Bad, because adding `isDemo` to the JWT requires custom callbacks.
|
|
|
|
### Clerk
|
|
|
|
- Good, because fully managed, beautiful UI, no session code to maintain.
|
|
- Bad, because requires third-party redirect; adds external dependency.
|
|
- Bad, because demo-user policy would require custom session metadata sync.
|
|
|
|
### Supabase Auth
|
|
|
|
- Good, because integrates with Supabase storage (but we use Neon).
|
|
- Bad, because username/password without email is not the primary use case.
|
|
- Bad, because adds a second database dependency just for auth.
|
|
|
|
### iron-session + bcryptjs
|
|
|
|
- Good, because minimal, explicit, and TypeScript-native.
|
|
- Good, because session payload is a plain object we fully control.
|
|
- Neutral, because we write our own password logic (bcrypt makes it safe).
|
|
|
|
## More Information
|
|
|
|
See `docs/patterns/iron-session.md` for implementation details. Revisit if multi-tenant or SSO requirements emerge.
|