Address 21 previously undefined behaviors across specs: - Authentication: Replace email/password with OIDC (Pocket-ID) - Cycle tracking: Add fixed-luteal phase scaling formula with examples - Calendar: Document period logging behavior (preserve predictions) - Garmin: Clarify connection is required (no phase-only mode) - Dashboard: Add UI states, dark mode, onboarding, accessibility - Notifications: Document timezone batching approach - New specs: observability.md (health, metrics, logging) - New specs: testing.md (unit + integration strategy) - Main spec: Add backup/recovery, known limitations, API updates Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
4.2 KiB
Authentication Specification
Job to Be Done
When I access PhaseFlow, I want to securely log in with my identity provider, so that my personal health data remains private.
Auth Provider
Using PocketBase for authentication and data storage, with OIDC (Pocket-ID) as the primary identity provider.
Connection:
POCKETBASE_URLenvironment variablesrc/lib/pocketbase.tsinitializes client
Login Flow
OIDC Authentication (Pocket-ID)
- User clicks "Sign In" on
/login - App redirects to Pocket-ID authorization endpoint
- User authenticates with Pocket-ID (handles MFA if configured)
- Pocket-ID redirects back with authorization code
- PocketBase exchanges code for tokens
- User redirected to dashboard
OIDC Configuration
Configure in PocketBase Admin UI: Settings → Auth providers → OpenID Connect
Required Settings:
Client ID- From Pocket-ID applicationClient Secret- From Pocket-ID applicationIssuer URL- Your Pocket-ID instance URL (e.g.,https://id.yourdomain.com)
Environment Variables:
POCKETBASE_OIDC_CLIENT_ID=phaseflow
POCKETBASE_OIDC_CLIENT_SECRET=xxx
POCKETBASE_OIDC_ISSUER_URL=https://id.yourdomain.com
Session Management
- PocketBase manages session tokens automatically
- Auth state persisted in browser (cookie/localStorage)
- Session expires after 14 days of inactivity
Pages
/login
Elements:
- "Sign In with Pocket-ID" button
- Error message display
Behavior:
- Redirect to
/on successful login - Show error message on failed attempt
- Rate limit: 5 attempts per minute
Protected Routes
All routes except /login require authentication.
Middleware Check:
- Check for valid PocketBase auth token
- If invalid/missing, redirect to
/login - If valid, proceed to requested page
API Authentication
User Context
API routes access current user via:
const pb = new PocketBase(process.env.POCKETBASE_URL);
// Auth token from request cookies
const user = pb.authStore.model;
Protected Endpoints
All /api/* routes except:
/api/calendar/[userId]/[token].ics(token-based auth)/api/cron/*(CRON_SECRET auth)
User API
GET /api/user
Returns current authenticated user profile.
Response:
{
"id": "user123",
"email": "user@example.com",
"garminConnected": true,
"cycleLength": 31,
"lastPeriodDate": "2024-01-01",
"notificationTime": "07:00",
"timezone": "America/New_York"
}
PATCH /api/user
Updates user profile fields.
Request Body (partial update):
{
"cycleLength": 28,
"notificationTime": "06:30"
}
User Schema
See src/types/index.ts for full User interface.
Auth-related fields:
id- PocketBase record IDemail- Login email
Profile fields:
cycleLength- Personal cycle length (days)notificationTime- Preferred notification hourtimezone- User's timezone
PocketBase Client (src/lib/pocketbase.ts)
Exports:
pb- Initialized PocketBase clientgetCurrentUser()- Get authenticated userisAuthenticated()- Check auth status
Settings Page (/settings)
User profile management:
- View/edit cycle length
- View/edit notification time
- View/edit timezone
- Link to Garmin settings
Success Criteria
- OIDC login flow completes in under 5 seconds (including redirect)
- Session persists across browser refreshes
- Unauthorized access redirects to login
- User data isolated by authentication
Acceptance Tests
- OIDC redirect initiates correctly
- Successful OIDC callback creates/updates user
- Session persists after page refresh
- Protected routes redirect when not authenticated
- GET
/api/userreturns current user data - PATCH
/api/userupdates user record - Logout clears session completely
- Auth cookie is HttpOnly and Secure
Future Enhancements
Open Registration
When open registration is enabled:
- Add
/signuppage with OIDC provider selection - New users created automatically on first OIDC login
- Admin approval workflow (optional)
Additional OAuth2 Providers
PocketBase supports multiple OAuth2 providers. Future options:
- GitHub
- Apple
- Other OIDC-compliant providers
Each provider configured separately in PocketBase Admin UI.