# TASK METADATA - **Target Files:** `server/auth-session.ts`, `server/routes/sessions.ts`, `server/routes/events.ts`, `server/main.ts`, `ui/mod.ts`, `server/main.test.ts` - **Core Objective:** Implement strict Zero-Trust scope enforcement and permission guards across all Auth-Yes internal API routes and SSR UI pages to ensure delegated and read-only sessions cannot escalate privileges, perform unauthorized mutations, or access admin interfaces. - **Dependencies:** None - **Additional Important Notes:** Delegated sessions (`is_agent = true`) must hold strictly the intersection of user permissions and assigned `custom_scopes`. Self-revocation of a delegated session is permitted, but revoking other sessions is prohibited without `write:sessions` or `*`. --- ## Architectural Considerations & Risks - **Risks:** - **Backward-Compatibility with Cached Sessions:** Existing delegated sessions in the Valkey cache might lack explicit scopes if they were created before this strict enforcement. The middleware must default to a safe deny state for unknown or missing scopes but handle legacy `is_agent = true` sessions gracefully by denying mutating actions unless explicitly permitted. - **Self-Revocation Edge Case:** The guard logic must correctly distinguish between a session revoking itself (which is always allowed for clean logouts) and a session attempting to revoke a sibling or parent session. - **Global Admin Resolution:** The `isGlobalAdmin` check relies on database queries or cache. Ensure that the new middleware does not introduce significant latency by repeatedly querying PostgreSQL on every protected route. Use Valkey caching where possible. - **Alternatives:** - Instead of injecting `customScopes` into the Valkey cache session payload, we could perform a database lookup on every privileged API request to determine exact grants. However, this violates the Auth-Yes architectural principle of fast-path caching at the edge and would significantly degrade performance. The chosen approach of checking scopes from the cached `AuthenticatedUser` object is highly modular and performant. ## Proposed Implementation ### 1. Scope Guard Helpers (`server/auth-session.ts`) Implement reusable composable functions to evaluate the current user's capabilities. - `hasScope(auth: AuthenticatedUser, requiredScope: string): boolean`: Evaluates if `auth.customScopes` contains `*` or the `requiredScope`. If `!auth.isAgent`, returns `true` (primary sessions have all capabilities). - Create Hono middleware helpers: - `requirePrimarySession()`: Denies access with `403 Forbidden` if `auth.isAgent === true`. - `requireScope(scope: string)`: Denies access if `hasScope(auth, scope)` returns false. - `requireAdmin(auth: AuthenticatedUser)`: Uses `isGlobalAdmin(auth.userId)` and verifies `!auth.isAgent` OR `auth.customScopes.includes("*")`. ### 2. Guard Internal API Routes Apply the newly created guards to critical endpoints. - **`server/routes/sessions.ts`** - `DELETE /api/sessions/:id`: Allow if target `id === auth.sessionId`. Otherwise, require `write:sessions` scope. - `PUT /api/sessions/:id/scopes`: Require `admin` or `*` scope, OR `write:sessions`. - `POST /api/sessions/:id/extend`: Require `write:sessions` or `*`. - `POST /api/sessions/delegate`: Prevent privilege escalation. Require `admin` or `*` scope to delegate an `admin` mode session. If creating a `read_only` or `operator` session, require the delegator to have at least those equivalent scopes. - **`server/routes/events.ts`** - `POST /api/events`: Require `write:events` or `*`. - `POST /api/events/:id/end`: Require `write:events` or `*`. - `POST /api/events/:id/extend`: Require `write:events` or `*`. - **`server/main.ts`** - Apply `requirePrimarySession()` or `requireAdmin()` to `/api/admin/*` and `/api/passkeys/*` endpoints. ### 3. SSR UI Gates (`ui/mod.ts`) Guard the user interfaces against unauthorized delegated sessions. - `/admin/*`: Verify `isAdmin && (!auth.isAgent || auth.customScopes.includes("*"))`. Redirect unauthorized sessions to `/dashboard` or return a `403 Forbidden` page. - `/dashboard/passkeys`: Verify `!auth.isAgent`. Delegated sessions cannot manage passkeys. ### 4. Testing (`server/main.test.ts`) - Write tests that create a delegated session with only `read_only` scopes. - Assert that this session gets a `403 Forbidden` when attempting to call `POST /api/sessions/delegate`, `DELETE /api/sessions/:other_id`, and `POST /api/events`. - Assert that the delegated session can successfully call `DELETE /api/sessions/:own_id`. - Write tests verifying that a delegated session attempting to access `/admin/users` is redirected/blocked.