#15334: feat: add multi-tenant REST API for BYOK multi-user support
gateway
stale
size: XL
Cluster:
Security Enhancements and Fixes
## 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
#20561: feat: add Sisyphus-style orchestration features
by dfggggx198601 · 2026-02-19
73.0%
#8821: Security: Holistic capability-based sandbox (replaces pattern-match...
by tonioloewald · 2026-02-04
72.6%
#12168: feat: integrate Mission Control dashboard into Control UI
by riftagent-git · 2026-02-08
72.4%
#13889: feat: Slack channel cache, session cost alerts & checkpoint/recover...
by trevorgordon981 · 2026-02-11
72.4%
#10367: CLI/Ops: resilient browser fill + failover hardening + operations t...
by cluster2600 · 2026-02-06
72.3%
#19885: test(gateway,browser): isolate tests from ambient OPENCLAW_GATEWAY_...
by NewdlDewdl · 2026-02-18
72.3%
#14309: fix(ui): resolve chat event session key mismatch
by justonlyforyou · 2026-02-11
72.2%
#20782: feat(gateway): Cloudflare Tunnel & Access integration
by G4brym · 2026-02-19
72.2%
#21589: Post-Performance Roadmap: Milestones A–D (contracts, observability,...
by Doji-Hammer · 2026-02-20
72.1%
#9006: fix: streaming UI, session locks, routing performance, plugin sandb...
by facundollamas2007 · 2026-02-04
72.0%