Authentication Flow
1. Authentication vs Authorization
TestoQA separates:
- Authentication: Who is the user?
- Authorization: What is the user allowed to do (within a project/tenant)?
This document covers authentication only: session establishment, identity resolution, and how identity is made available to server-side boundaries.
Authorization logic and enforcement locations are defined in authorization-model.mdx.
2. Entry Points Requiring Authentication
Most tenant-sensitive operations require authentication at the boundary layer:
- Server Actions that read or mutate tenant data
- Route Handlers that access tenant data or trigger workflows
- Any file upload initiation that persists metadata or grants access
- Any realtime authorization endpoints (if applicable)
Some routes may be public (e.g., marketing pages), but tenant data is never public.
3. Session Establishment (Login)
Authentication is implemented using Auth.js (NextAuth v5) with a session-based model.
At a high level:
- A user initiates sign-in.
- Auth.js performs provider authentication.
- A session is created/persisted (via adapter).
- The browser receives a session cookie/token.
- Subsequent requests can resolve the session server-side.
Provider and adapter specifics are intentionally not documented here. This file defines the architectural behavior.
4. Session Resolution
Every authenticated request resolves identity server-side. UI state is never trusted as identity.
Where session is resolved
Session resolution occurs within:
- Server Components (for SSR gating / conditional rendering)
- Server Actions
- Route Handlers
What session resolution produces
Session resolution yields a normalized identity, typically including:
userId- basic user attributes needed for request context resolution
This identity becomes input to RequestContext resolution at boundaries.
5. Identity Propagation Into RequestContext
Authentication alone is not sufficient to perform tenant operations.
Boundaries must create a RequestContext that includes:
userId(from session)projectId(resolved and verified; seetenancy-model.mdx)- any additional request metadata used for logging/observability
Rule: The RequestContext is resolved at the boundary before doing work.
6. Authenticated Request Flow (Typical)
The typical authenticated request lifecycle:
Browser
→ Next.js App Router
→ Server Action / Route Handler
→ Resolve session (Auth.js)
→ Construct RequestContext (userId + projectId)
→ Proceed to authorization (separate step)
→ Call domain services
→ Repositories (tenant-scoped)
→ Prisma → PostgreSQL
→ Response
Key constraints:
- Authentication is always resolved server-side.
- Tenant resolution is explicit; it must not be guessed.
- Authorization occurs before data access.
7. Unauthenticated Request Handling
When session resolution fails:
- The request is treated as unauthenticated
- The system must return an appropriate failure response:
- redirect to sign-in where applicable (UI routes)
- 401/unauthorized for API-like handlers (route handlers)
Do not leak information
Unauthenticated responses must not reveal:
- whether a particular project exists
- whether a resource exists inside a project
- membership details
8. Session Expiry and Renewal
Session expiry is expected and must be handled safely:
- A stale/expired session results in unauthenticated behavior
- Boundaries must treat session absence as a hard stop for tenant operations
- UI should handle re-authentication flows gracefully
Renewal mechanisms are implementation details; the architectural invariant is:
No session ⇒ no tenant work.
9. Security Considerations
Client is never authoritative
- Client state cannot assert identity
- Client-supplied identifiers must be validated server-side
CSRF posture
Any non-idempotent operation must consider CSRF posture. The architectural requirement is:
- mutating operations must be protected via framework/auth mechanisms suitable for the session model
Avoid logging sensitive auth artifacts
- Never log session tokens/cookies
- Be careful logging headers, especially in error scenarios
10. Review Checklist (Authentication)
- Does every tenant-sensitive boundary resolve session server-side?
- Does the boundary fail fast when unauthenticated?
- Is
RequestContextcreated from trusted sources only? - Are unauthenticated responses tenant-safe (no leakage)?
- Are auth artifacts excluded from logs?