OAuth account proxy for OpenCode. One base URL for Copilot, Codex, and Claude.
Note
"Kleis" is named from the idea of a key that can unlock many paths with one handle.
Re-authenticating OAuth accounts across clients and machines is painful. Kleis stores credentials centrally, refreshes tokens automatically, and lets clients authenticate with simple API keys.
Each provider has its own proxy adapter because none of them behave the same way. Copilot needs vision/initiator headers derived from message content analysis. Codex rejects certain params and requires instruction injection. Claude needs tool name prefixing, system identity rewriting, beta header merging, and streaming response transformation to strip those prefixes back out.
GET /api.json serves a models.dev-compatible registry that merges upstream model data with Kleis routing info, so OpenCode auto-discovers everything without manual model config.
Each API key also gets a scoped discovery URL at GET /api/<models-discovery-token>/api.json, so model discovery can match that key's provider/model scopes.
There's also minute-bucketed request analytics across both API keys and provider accounts (non-blocking on the proxy path), and a small admin panel for managing accounts, keys, and token refreshes.
| Route | Provider | Endpoint |
|---|---|---|
POST /openai/v1/responses |
Codex | Responses API |
POST /anthropic/v1/messages |
Claude | Messages API |
POST /copilot/v1/chat/completions |
Copilot | Chat Completions |
POST /copilot/v1/responses |
Copilot | Responses API |
bun installCreate .env:
ADMIN_TOKEN=replace-with-a-long-random-token
CRON_SECRET=replace-with-a-long-random-token
TURSO_CONNECTION_URL=libsql://<your-db>.<region>.turso.io
TURSO_AUTH_TOKEN=<your-turso-token>bun run db:migrate
bun run devAdmin panel lives at http://localhost:3000/admin/.
- Codex: browser callback code flow or headless device flow.
- Copilot: device flow.
- Claude: authorization code flow (
claude.aiorconsole.anthropic.commode).
After connecting accounts, set one primary account per provider.
After creating an API key in the admin panel:
OPENCODE_MODELS_URL=https://your-kleis-domain/api/<models-discovery-token>
KLEIS_API_KEY=your-issued-keySet ADMIN_TOKEN, CRON_SECRET, TURSO_CONNECTION_URL, and TURSO_AUTH_TOKEN in your Vercel project, then deploy. Migrations run on build. Bun runtime.
vercel.json includes a daily cron that calls GET /cron/refresh-provider-accounts to force-refresh all saved provider accounts.
Build pre-bundles everything into dist/index.js because Vercel's @vercel/node esbuild pass can't resolve extensionless TypeScript imports (vercel/vercel#14910) unless you use an experimental flag, which... breaks serving files from the public directory. Filed vercel/vercel#15216 to fix this.
Hono · Turso (libSQL) · Drizzle ORM · Zod · Bun
Provider proxy behavior is derived from OpenCode and pi-mono. Source references are pinned to specific commits throughout the codebase.
