auth-yes/tasks/new/2026-0826.01.jul.story.events.phase-1-guest-ingress-1400.md
google-labs-jules[bot] 4ec15fe35f docs: add task plan for phase 1 of events guest ingress
Adds the task definition markdown file `2026-0826.01.jul.story.events.phase-1-guest-ingress-1400.md` detailing the architectural scope and plan for enabling Traefik ForwardAuth guest ingress, bridging custom scopes to the Launchpad UI via UNION query, and wiring event claim audit logs using event.id.

Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com>
2026-08-26 22:00:56 +00:00

4.6 KiB

TASK METADATA

  • Target Files: server/routes/auth_forward.ts, ui/db_queries.ts, ui/mod.ts, server/routes/events.ts, server/tests/forward_auth.test.ts, server/tests/events.test.ts
  • Core Objective: Implement Phase 1 of the Event & Session Overhaul: Enable Traefik ForwardAuth guest ingress for scoped event attendees, bridge session custom scopes to the Launchpad UI, and wire audit logging on event seat claims.
  • Dependencies: None.
  • Additional Important Notes: Follow zero-trust default-deny principles for ForwardAuth. Guest sessions minting needs to correctly log to the Merkle audit ledger for SIEM visibility.

2. Architectural Considerations & Risks

  • Risks:

    • ForwardAuth Security: Modifying ForwardAuth to accept guest accounts risks inadvertently allowing guests to access applications they are not explicitly scoped for. Strict validation of auth.customScopes against the requested appRecord.name is critical.
    • Launchpad Leakage: The getDashboardApps query modification must be robust. If the UNION query is not correctly structured, it could leak visibility of unregistered or unauthorized apps to guests.
    • Audit Logging Integrity: Failure to capture the audit events properly during the join phase would break SIEM visibility. Using the non-blocking auditWrapper.auditLog is required to avoid impacting user request latency while ensuring compliance.
  • Alternatives:

    • We considered a bypass in ui/db_queries.ts where guests completely skip the grants JOIN. However, using a UNION is structurally superior as it seamlessly supports both pure guests and regular active users who might hold delegated scoped passes. It provides a unified data retrieval flow.

3. Proposed Implementation

Phase 1: ForwardAuth Guest Ingress (server/routes/auth_forward.ts)

  1. Permit Guest Accounts: Update the account status validation to allow user.account_status === 'guest' in addition to 'active'.
  2. Custom Scopes Validation: If the user is a guest (or relying on custom scopes), verify that auth.customScopes contains the explicit application grant (e.g., app:${appRecord.name}). If not, return a 403 Forbidden.
  3. Header Injection: For guest sessions, compute the scopes to inject into X-Forwarded-Scopes by taking the comma-joined list of auth.customScopes (auth.customScopes.join(",")). This propagates the app scope (e.g., app:ed-droid) and role (e.g., viewer) to downstream reverse proxies.

Phase 2: Launchpad App Query (ui/db_queries.ts & ui/mod.ts)

  1. Function Signature Update: Update getDashboardApps(userId: string, isAdmin: boolean, customScopes?: string[]) to accept the session's custom scopes.
  2. UNION Query: Update the non-admin SQL query to use a UNION.
    • The first part queries explicitly granted apps via the grants table.
    • The second part parses the provided customScopes array to extract allowed app names (e.g., stripping the app: prefix), querying the apps table for those matching names, and assigning them a pseudo-role such as "Guest (Viewer)" (or extracting the role from the scopes if possible).
  3. UI Integration: In ui/mod.ts, pass auth.customScopes from the resolved session into getDashboardApps.

Phase 3: Join Audit Logging (server/routes/events.ts)

  1. Audit POST /api/join (Web): Immediately after minting the guest session, invoke auditWrapper.auditLog(guestUuid, "event_seat_claimed", event.id, { slug: event.slug, name: event.name, seatNumber: event.seats_claimed, method: "web" }, getClientIp(c)).
  2. Audit GET /join/:slug (CLI): Similarly, wire auditWrapper.auditLog(guestUuid, "event_seat_claimed", event.id, { slug: event.slug, name: event.name, seatNumber: event.seats_claimed, method: "cli" }, getClientIp(c)) into this endpoint before returning the token.

Phase 4: Unit Testing

  1. ForwardAuth Tests (server/tests/forward_auth.test.ts):
    • Add tests simulating a guest session with an app:{name} scope to ensure a 200 OK response with correctly formatted X-Forwarded-Scopes.
    • Add tests simulating a guest session without the necessary app:{name} scope to ensure a 403 Forbidden response.
  2. Events Tests (server/tests/events.test.ts):
    • Ensure the POST /api/join and GET /join/:slug assertions capture the auditLog spy calls and verify the exact payload (event_seat_claimed action, event.id as resource, correct metadata structure).