Files
phaseflow/specs/authentication.md
Petru Paler 3567fbafd7
Some checks failed
Deploy / deploy (push) Failing after 6m37s
Expose PocketBase URL to client-side for OIDC auth
POCKETBASE_URL was only available server-side, causing the login page
to fall back to localhost:8090 in the browser. Renamed to
NEXT_PUBLIC_POCKETBASE_URL so Next.js bundles it into client code.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 17:33:52 +00:00

4.3 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:

  • NEXT_PUBLIC_POCKETBASE_URL environment variable
  • src/lib/pocketbase.ts initializes client

Login Flow

OIDC Authentication (Pocket-ID)

  1. User clicks "Sign In" on /login
  2. App redirects to Pocket-ID authorization endpoint
  3. User authenticates with Pocket-ID (handles MFA if configured)
  4. Pocket-ID redirects back with authorization code
  5. PocketBase exchanges code for tokens
  6. User redirected to dashboard

OIDC Configuration

Configure in PocketBase Admin UI: Settings → Auth providers → OpenID Connect

Required Settings:

  • Client ID - From Pocket-ID application
  • Client Secret - From Pocket-ID application
  • Issuer 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:

  1. Check for valid PocketBase auth token
  2. If invalid/missing, redirect to /login
  3. If valid, proceed to requested page

API Authentication

User Context

API routes access current user via:

const pb = new PocketBase(process.env.NEXT_PUBLIC_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 ID
  • email - Login email

Profile fields:

  • cycleLength - Personal cycle length (days)
  • notificationTime - Preferred notification hour
  • timezone - User's timezone

PocketBase Client (src/lib/pocketbase.ts)

Exports:

  • pb - Initialized PocketBase client
  • getCurrentUser() - Get authenticated user
  • isAuthenticated() - 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

  1. OIDC login flow completes in under 5 seconds (including redirect)
  2. Session persists across browser refreshes
  3. Unauthorized access redirects to login
  4. 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/user returns current user data
  • PATCH /api/user updates user record
  • Logout clears session completely
  • Auth cookie is HttpOnly and Secure

Future Enhancements

Open Registration

When open registration is enabled:

  • Add /signup page 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:

  • Google
  • GitHub
  • Apple
  • Other OIDC-compliant providers

Each provider configured separately in PocketBase Admin UI.