# Gateway Trust Model ## Architecture All frontend requests go through: Browser → Pangolin → frontend-v2 (SvelteKit hooks) → gateway → backend services. ## Authentication Layers ### Gateway (platform auth) - Users authenticate via `/api/auth/login` with username/password (bcrypt) - Session stored as `platform_session` cookie (HttpOnly, Secure, SameSite=Lax) - All `(app)` routes require valid session (checked in `+layout.server.ts`) - Registration is disabled (returns 403) ### Service-level auth Services fall into two categories: **Per-user token services** — each platform user has their own service credential: | Service | Auth Type | How Injected | Per-User Data? | |---------|-----------|-------------|----------------| | Trips | Bearer token | `Authorization: Bearer {token}` | No — all users see all trips | | Fitness | Bearer token | `Authorization: Bearer {token}` | **Yes** — each user has own entries, goals, favorites | **Gateway-key services** — a single API key shared by all platform users: | Service | Auth Type | How Injected | Per-User Data? | |---------|-----------|-------------|----------------| | Inventory | API key | `X-API-Key: {key}` | No — single shared inventory | | Budget | API key | `X-API-Key: {key}` | No — single shared budget | | Reader | API key | `X-Auth-Token: {key}` | No — single shared feed reader | | Books (Shelfmark) | None | Proxied through gateway | No — single shared download manager | | Music (Spotizerr) | None | Proxied through gateway | No — single shared music downloader | **Important**: Gateway-key services do NOT have per-user data isolation. Any authenticated platform user can access all data in these services. This is by design — the household shares a single budget, inventory, reader, and media library. ### Frontend hooks auth (SvelteKit) - Immich proxy: validates `platform_session` cookie before proxying - Karakeep proxy: validates `platform_session` cookie before proxying - Legacy trips Immich: validates `platform_session` cookie before proxying ## Service Connections - Users connect per-user services (trips, fitness) via Settings page - Token validation uses a **protected endpoint** per service type — not health checks - Unknown services cannot be connected (rejected with 400) - Tokens stored in `service_connections` table, per-user ## Per-User Navigation - Each user sees only their configured apps in the navbar - Configured via `hiddenByUser` map in `+layout.server.ts` - Apps not in nav are still accessible via direct URL (not blocked) ## Internal Network - All services communicate on Docker internal network via plain HTTP - No service port is exposed to the host (except frontend-v2 via Pangolin) - Gateway is the single entry point for all API traffic - No custom SSL context — all internal calls are plain HTTP ## TLS - External HTTPS (OpenAI, SMTP2GO, Open Library): default TLS verification - Internal services: plain HTTP (Docker network, no TLS needed) - Image proxy: default TLS verification + domain allowlist + content-type validation ## Secrets - All secrets loaded from environment variables - No hardcoded credentials in code - `.env` files excluded from git - Admin credentials required via `ADMIN_USERNAME`/`ADMIN_PASSWORD` env vars - Service API keys generated per service, stored in `.env` ## Known Limitations - Gateway-key services are shared — no per-user access control - Books and Music services have no auth at all (rely on gateway session only) - Shelfmark and Spotizerr accept any request from the Docker network - Per-user nav hiding is cosmetic — direct URL access is not blocked