# 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 session minting must 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 SQL Array Guard:** If a user or guest has no `app:` custom scopes, passing an empty array into an `IN ()` clause causes invalid SQL. The query must use `if (appNames.length > 0)` or `WHERE name = ANY(${appNames}::text[])`. - **Audit Logging Integrity:** Failure to capture the audit events properly during the `join` phase would break SIEM visibility. Using the non-blocking `auditWrapper.auditLog` with `getClientIp(c)` is required. - **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 (around line 120) 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}` or wildcard `*`). 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.filter(Boolean).join(",") || "viewer"`). 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 with Array Guard:** - Extract app names from `customScopes` (e.g. scopes starting with `app:`). - If `appNames.length > 0`, execute a `UNION` with `SELECT id, name, description, domain, 'Guest (Viewer)' as role FROM apps WHERE domain IS NOT NULL AND name = ANY(${appNames}::text[])`. - If `appNames.length === 0`, return only the primary `grants` query result. 3. **UI Integration:** In `ui/mod.ts` under `/dashboard`, pass `auth.customScopes` from the resolved session into `getDashboardApps`. ### Phase 3: Join Audit Logging (`server/routes/events.ts`) 1. **Import `getClientIp`:** Import `getClientIp` from `../middleware.ts`. 2. **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))`. 3. **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))`. ### Phase 4: Unit Testing 1. **ForwardAuth Tests (`server/tests/forward_auth.test.ts`):** - Add test: `Tier 1 & 2: GET /api/forward-auth - Guest session with app scope allowed`. - Add test: `Tier 1 & 2: GET /api/forward-auth - Guest session without app scope rejected (403)`. 2. **Events Tests (`server/tests/events.test.ts`):** - Ensure the `POST /api/join` and `GET /join/:slug` assertions verify the `auditLog` call payload (`event_seat_claimed` action, `event.id` as resource, and correct metadata structure).