Skip to content

Pipeline Plan 15

Seth Ford edited this page Feb 12, 2026 · 2 revisions

Let me write the plan directly. Here's the implementation plan:


Implementation Plan: Add Dashboard Authentication (GitHub OAuth) — Issue #15

Key Finding

The OAuth flow is already 90% implemented in dashboard/server.ts. The existing code includes: OAuth redirect, callback/token exchange, session cookies, auth gate, login page, PAT fallback, logout, and /api/me. This plan focuses on the security gaps and missing features.


Files to Modify

File Action Purpose
dashboard/server.ts Modify Add CSRF state param, developer auto-registration, secure cookie flag, heartbeat identity validation, admin vs. write distinction
dashboard/server-auth-test.ts Create Unit tests for auth flow

Implementation Steps

Step 1: Add OAuth CSRF state parameter protection

  • In handleAuthGitHub() (line 1922): Generate a random state token using crypto.randomUUID(), store it in a short-lived map with a 10-minute TTL
  • Add state to the OAuth authorize URL params
  • In handleAuthCallback() (line 1939): Validate the state parameter matches the stored value before exchanging the code

Step 2: Add Secure flag to session cookies in production

  • In sessionCookie() (line 214): Detect if running behind HTTPS (check DASHBOARD_SECURE env var or default to true when NODE_ENV=production) and add Secure flag conditionally
  • Update clearSessionCookie() (line 218) to match

Step 3: Distinguish admin vs. write permission

  • In handleAuthCallback() (line 1958-1959): Set isAdmin to true only for "admin" and "maintain" permissions. Users with "write"/"push" permission still get access but isAdmin = false
  • Same change in handlePatLogin() (line 2019-2020)
  • Update ALLOWED_PERMISSIONS (line 41) to include "maintain"

Step 4: Developer auto-registration on first OAuth login

  • After session creation in handleAuthCallback() (after line 1974): Register the user in the developer registry if not already present
  • Create a registerOAuthDeveloper(username, avatarUrl) helper that adds an entry to developerRegistry with developer_id set to the GitHub username, machine_name as "dashboard", and a current heartbeat timestamp
  • Same logic in handlePatLogin() after session creation

Step 5: Heartbeat endpoint validates developer identity

  • In the /api/connect/heartbeat handler (line 3764): When auth is enabled, check if the request has a valid session cookie. If it does, verify the developer_id in the body matches the session's githubUser
  • Allow existing invite-token auth as fallback for CLI-based heartbeats (which don't have browser sessions)
  • This means heartbeats can be authenticated via either: (a) session cookie (dashboard), or (b) invite token (CLI)

Step 6: Write auth tests

  • Create dashboard/server-auth-test.ts with Bun test runner
  • Test cases: OAuth state generation/validation, session creation/expiry, cookie flags, public vs. protected route access, developer auto-registration, admin vs. write distinction, heartbeat identity validation

Task Checklist

  • Task 1: Add OAuth state parameter to /auth/github redirect and validate in /auth/callback (CSRF protection)
  • Task 2: Add Secure cookie flag when serving over HTTPS (env-controlled)
  • Task 3: Distinguish admin (admin/maintain) vs. collaborator (write/push) permissions — both get access, only admin gets isAdmin: true
  • Task 4: Auto-register developers in the registry on first OAuth/PAT login
  • Task 5: Validate developer identity on heartbeat endpoint when auth is enabled
  • Task 6: Add ALLOWED_PERMISSIONS to include "maintain" and "push" for access (keep admin distinction separate)
  • Task 7: Write unit tests for the auth flow
  • Task 8: Update /api/me to return admin vs. collaborator role info
  • Task 9: Run existing test suite to ensure no regressions

Testing Approach

  1. Unit tests (dashboard/server-auth-test.ts): Test OAuth state generation/validation, session lifecycle, cookie flags, route protection, developer registration, permission mapping
  2. Existing test suite: Run npm test to verify no regressions in the 22 existing test suites
  3. Manual verification: Set GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, DASHBOARD_REPO env vars and test the full OAuth flow in a browser

Definition of Done

  • OAuth flow includes CSRF state parameter validation
  • Session cookies include Secure flag when configured for HTTPS
  • Public routes (/login, /auth/callback, /api/health) work without authentication
  • All other routes redirect to /login when no session exists
  • First-time OAuth login auto-registers developer in registry
  • Admin flag correctly distinguishes admin/maintain from write/push permissions
  • Heartbeat endpoint validates developer identity against session when auth is enabled
  • All existing tests pass (npm test)
  • New auth-specific tests pass

Shall I proceed with the implementation? The changes are concentrated in a single file (dashboard/server.ts) plus a new test file, making this well-suited for sequential work rather than a team.

Clone this wiki locally