← Back to PRs

#15334: feat: add multi-tenant REST API for BYOK multi-user support

by 0xpaperhead open 2026-02-13 09:09 View on GitHub →
gateway stale size: XL
## Summary - Adds a complete multi-tenant layer allowing multiple users to share a single OpenClaw gateway with isolated agents, sessions, and LLM credentials (Bring Your Own Key) - Admin CRUD endpoints for tenant management (`POST/GET/PATCH/DELETE /api/v1/tenants`) - Tenant-facing chat endpoint with sync and SSE streaming (`POST /api/v1/chat`), plus session management (`GET/DELETE /api/v1/sessions`) - Gated behind `OPENCLAW_MULTITENANT=1` env var — zero overhead when disabled ## New files | File | Purpose | |------|---------| | `src/multitenant/tenant-crypto.ts` | API key generation, SHA-256 hashing, AES-256-GCM encryption of LLM keys at rest | | `src/multitenant/tenant-paths.ts` | Per-tenant directory resolution mapping to standard agent layout | | `src/multitenant/tenant-store.ts` | Tenant CRUD with file-based JSON storage + `proper-lockfile` concurrency | | `src/multitenant/tenant-auth.ts` | Request authentication middleware (tenant Bearer + admin token) | | `src/multitenant/tenant-api.ts` | Admin REST endpoints for tenant lifecycle | | `src/multitenant/tenant-chat.ts` | Chat endpoint + session management (modeled after `openai-http.ts`) | | `src/multitenant/tenant-http.ts` | Route aggregator with feature flag gate | ## Modified files - `src/gateway/server-http.ts` — wires tenant handler into the HTTP request chain ## Design decisions - **Logical isolation**: tenants share one gateway process; isolation is via tenant-scoped agent directories (`$STATE_DIR/agents/tenant-{id}/agent/`) - **BYOK**: tenant's LLM API key is written into the standard `auth-profiles.json` format so existing auth profile resolution works without modification - **No agentCommand validation bypass needed**: passing only `sessionKey` (not `agentId`) to `agentCommand()` naturally skips config-based agent validation; agent ID is inferred from session key - **Platform API keys**: `ocpk_` prefixed, SHA-256 hashed for O(1) lookup - **Encryption**: AES-256-GCM for LLM API keys at rest, master key from `OPENCLAW_TENANT_MASTER_KEY` ## Test plan - [ ] Enable with `OPENCLAW_MULTITENANT=1` and `OPENCLAW_ADMIN_TOKEN=<secret>` and `OPENCLAW_TENANT_MASTER_KEY=<32+ char key>` - [ ] Create tenant via `POST /api/v1/tenants` with admin token - [ ] Send chat message via `POST /api/v1/chat` with tenant's platform API key - [ ] Verify SSE streaming works with `Accept: text/event-stream` - [ ] Verify tenant isolation (tenant A cannot access tenant B's sessions) - [ ] Verify gateway works normally when `OPENCLAW_MULTITENANT` is unset - [ ] `pnpm build && pnpm check && pnpm test` all pass <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR introduces a feature-flagged multi-tenant HTTP API under `/api/v1/*`, wiring it into the gateway request chain (`src/gateway/server-http.ts`). It adds: - Admin tenant lifecycle endpoints (`src/multitenant/tenant-api.ts`) backed by a file-based tenant registry with locking (`src/multitenant/tenant-store.ts`). - Tenant auth middleware (`src/multitenant/tenant-auth.ts`) using Bearer tokens mapped via a SHA-256 key index. - A tenant chat endpoint with sync and SSE streaming plus basic session listing (`src/multitenant/tenant-chat.ts`). - Crypto utilities for API key generation, hashing, and AES-256-GCM encryption at rest (`src/multitenant/tenant-crypto.ts`). Key issues to address before merge: - Admin auth currently uses a non–timing-safe equality check despite claiming constant-time. - The chat API accepts arbitrary `session_id` values that can later break transcript/session path logic due to stricter validation elsewhere. - The sessions API currently returns session *keys* under a `session_id` field and the DELETE route doesn’t actually delete anything, leaving the endpoint semantics inconsistent. <h3>Confidence Score: 3/5</h3> - This PR is close to mergeable but needs fixes in auth and session semantics to avoid security and correctness issues. - Core routing and storage wiring is straightforward and feature-flagged, but there are a few concrete issues that will cause real problems: admin token comparison is not timing-safe as implemented, caller-provided session IDs can violate downstream validation and throw, and the sessions API currently returns misleading identifiers with a non-functional delete route. - src/multitenant/tenant-auth.ts, src/multitenant/tenant-chat.ts <sub>Last reviewed commit: d5a9eb6</sub> <!-- greptile_other_comments_section --> <sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub> <!-- /greptile_comment -->

Most Similar PRs