ADR-019: Authentication & Session Management
Status: Planning Owner: @bilal @deen Date: 2026-02-15
Why This Needs an ADR
There’s ambiguity in the codebase. The CI/CD doc references both NEXTAUTH_SECRET/NEXTAUTH_URL and Supabase Auth. Three distinct auth flows exist across the product but no single doc explains how they relate:
- Landlord dashboard — Supabase Auth (email/password, possibly magic link)
- Tenant chat — Supabase Phone/Email OTP (ADR-016 Tenant Chat App)
- Vendor acceptance — Stateless token links (ADR-006 Vendor Acceptance Tokens)
Questions to Resolve
1. Supabase Auth vs NextAuth — which and why?
The .env.example has both NEXTAUTH_SECRET and SUPABASE_ANON_KEY. Are both in use? Options:
| Approach | Pros | Cons |
|---|---|---|
| Supabase Auth only | Single auth system, RLS works natively, OTP built-in | Less flexibility for custom session claims |
| NextAuth wrapping Supabase | Custom session handling, familiar API | Two systems to maintain, RLS bypass risk |
| NextAuth replaced by Supabase middleware | Simpler stack, native Supabase ecosystem | Migration effort if NextAuth is already used |
Likely answer: Supabase Auth only. NextAuth references may be legacy from early setup. Need to verify in codebase.
2. JWT Claims Structure
For multi-org support (ADR-001 Multi-Tenancy Access Model), the session needs to carry:
// What needs to be in the JWT/session
{
userId: string
email: string
organisationId: string // Currently selected org
organisationIds: string[] // All accessible orgs
role: 'owner' | 'admin' | 'staff' | 'envo_support'
}How does organisationId get into the session?
- Option A: Custom JWT claims via Supabase Auth hooks
- Option B: App-level session enrichment after Supabase auth
- Option C: Supabase
app.current_org_idsession variable for RLS
3. Multi-Org Session Switching
When a user has access to multiple orgs:
- How do they switch? (Dropdown in header? Separate login?)
- Does switching invalidate the current session?
- How does the GraphQL context get the current org?
4. Auth Middleware Architecture
Request → Supabase Auth check → Extract user → Load org access → Set context
↓
GraphQL resolvers
use ctx.organisationId
What middleware pattern? Next.js middleware? Per-route handler? Pothos auth plugin?
5. Tenant Auth (Chat App)
- Supabase Phone OTP — does this create a
usersrecord or a separate auth identity? - How does the OTP session map to a
tenantsrecord? - Is the tenant auth session completely separate from the dashboard auth?
6. Dev Auth
- ADR-016 mentions cookie-based tenant impersonation for dev
- Does the dashboard have similar dev shortcuts?
- How do seed users (Infrastructure) relate to auth?
Depends On
- Current codebase state (is NextAuth actually used?)
- Supabase Auth capabilities (custom claims, hooks)