# ADR-001: Session-Based Authentication with httpOnly Cookies

## Status

Accepted

## Context

The application needs an authentication mechanism for the OAuth2 flow with Authentik. We need to decide between:

1. **JWT tokens** stored in localStorage (common SPA pattern)
2. **Session cookies** with httpOnly flag
3. **JWT tokens** in httpOnly cookies

### Constraints

- Frontend and API run on different subdomains in production (e.g., `app.example.com` and `api.example.com`)
- Must support OAuth2 authorization code flow
- Must work with Traefik reverse proxy
- Must be secure against XSS attacks

## Decision

We will use **session-based authentication with HMAC-signed httpOnly cookies**.

### Implementation

1. After OAuth callback, the API creates a session token (HMAC-SHA256 signed)
2. Token is stored in an httpOnly, Secure, SameSite cookie
3. Frontend never sees or stores the token
4. Cookie is sent automatically with every request via `withCredentials: true`
5. Session is stateless - token contains user_id and expiry

## Consequences

### Positive

- **XSS protection**: Token is never exposed to JavaScript
- **Simpler frontend**: No token management, refresh logic, or storage
- **Immediate revocation**: Can invalidate sessions server-side if needed
- **Standards compliant**: Uses well-established cookie security mechanisms
- **Works across subdomains**: Cookie domain can be set to parent domain

### Negative

- **CSRF risk**: Requires CSRF protection for state-changing operations (mitigated by SameSite=Lax/Strict)
- **Less flexible**: Harder to use with non-browser clients (mitigated by API key support if needed)
- **Cookie size**: Session token adds ~100 bytes to every request

### Alternatives Considered

**JWT in localStorage**
- Pros: Simple implementation, works with any client
- Cons: Vulnerable to XSS, requires manual token refresh, complex frontend logic
- Rejected due to XSS vulnerability

**JWT in httpOnly cookies**
- Pros: XSS protection, standard JWT benefits
- Cons: Complex refresh token rotation, no easy revocation, larger token size
- Rejected in favor of simpler session cookies

## Date

2026-05-18

## Participants

- Development Team
