docs: draft task file for Ingress Grant Injection in forward-auth

Creates a new task markdown file in `tasks/new` detailing the
architecture and implementation steps required to inject
flattened RBAC grants via Valkey caching for `/api/forward-auth`.

Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com>
This commit is contained in:
google-labs-jules[bot] 2026-08-24 03:56:04 +00:00
parent cf64161a8b
commit 38310f4ead

View File

@ -0,0 +1,82 @@
# TASK METADATA
- **Target Files:** `server/main.ts`, `server/db.ts`, `server/auth-session.ts`
- **Core Objective:** Implement Ingress Grant Vector Injection in
`/api/forward-auth` to resolve `X-Forwarded-Host` against registered apps,
evaluate RBAC grants via Valkey caching, and inject flattened user grant
headers into downstream requests.
- **Dependencies:** Valkey caching infrastructure, database migration for
`domain` column on `apps` table.
- **Additional Important Notes:** Latency is critical; ForwardAuth must resolve
in <30μs using Valkey and must not hit PostgreSQL on every request. Global
Admins bypass app-specific grant checks.
---
## Architectural Considerations & Risks
### Risks
- **Cache Invalidation:** Stale data in Valkey could allow revoked users to
retain access or prevent newly granted users from accessing apps. We must
ensure that grants and app updates properly invalidate or update their
respective Valkey keys.
- **Header Spoofing / Parsing Issues:** Ensure the `X-Forwarded-*` headers are
safely injected and override any existing headers from the client to prevent
privilege escalation (handled by Traefik, but good to be mindful of).
- **Performance Bottlenecks:** While caching resolves database latency, improper
cache interactions (e.g., waiting for multiple sequential round-trips to
Valkey instead of using pipelining or MGET where appropriate) could still add
overhead.
### Alternatives Evaluated
- **Direct PostgreSQL queries:** Rejected due to the high volume of requests
hitting the edge proxy `/api/forward-auth`.
- **JWT Injection:** Instead of flattened headers, injecting a signed JWT was
considered. However, flattened headers (`X-Forwarded-User-Id`,
`X-Forwarded-Scopes`) are native to Traefik ForwardAuth and simpler for
downstream SSR hydration without requiring public key distribution to every
downstream app.
## Proposed Implementation
### 1. Database Schema Update (`server/db.ts`)
- Modify `initDb()` to add the `domain` column to the `apps` table:
`ALTER TABLE apps ADD COLUMN IF NOT EXISTS domain TEXT;`.
- Ensure application seeding or registry logic accounts for the new `domain`
field if necessary.
### 2. Caching Strategy Implementation
- Implement helper functions to fetch from Valkey or fallback to DB and populate
Valkey.
- **App Resolution Cache (`auth:app_by_host:<host>`):**
- Match `X-Forwarded-Host` against `apps.domain`.
- Fallback: Match `apps.name` against the first subdomain segment.
- Cache the resulting `app_id` and `name` in Valkey as JSON.
- **Grants Cache (`auth:grants:<userId>:<appId>`):**
- Cache the user's roles for the specific app.
### 3. ForwardAuth Endpoint Logic (`server/main.ts`)
- Update `GET /api/forward-auth` to:
1. Extract `X-Forwarded-Host` from the request.
2. Resolve the target application via the App Resolution Cache (Valkey). If no
app matches, decide whether to allow pass-through without scopes or
strictly deny (typically 403 for protected routes without an app, or allow
pass-through if unmapped). Assuming strict mapping per requirements, return
403 or 404 if not found.
3. Validate the user session (existing logic).
4. Check if the user is a Global Admin (`isGlobalAdmin`). If yes, authorize
automatically and set `X-Forwarded-Scopes: admin`.
5. For regular users, resolve their scopes for the target app via the Grants
Cache (Valkey).
6. Enforce Default-Deny: If no scopes are found, return 403 Forbidden.
7. On success, inject headers:
- `X-Forwarded-User-Id: <user.id>`
- `X-Forwarded-User-Name: <user.username>`
- `X-Forwarded-Scopes: <comma-separated list of roles>`
- `X-Forwarded-App-Id: <app_id>`
- Return HTTP 200 OK.