Secret vaults
A secret vault is a project-scoped, envelope-encrypted bucket of
named credentials. Each project designates one vault; platform-side
tools (the LLM provider router, the Brave search primitive, MCP
servers via auth.tokenRef) resolve credentials from it at call
time. The agent’s JS sandbox cannot read secrets directly —
they’re tool-internal.
The vault’s storage is envelope encryption: a per-row DEK
(AES-256-GCM) wrapped with the platform KEK (TAVORA_SECRET_KEK
today; KMS adapter on roadmap).
vault, _ := client.CreateSecretVault(ctx, tavora.CreateSecretVaultInput{ Name: "stripe-prod",})
_, _ = client.PutSecret(ctx, vault.ID, "stripe_secret_key", "sk_live_...")view, _ := client.ListSecrets(ctx, vault.ID)// view = []RedactedSecret{ {Name: "stripe_secret_key", KEKID: "..."} ... }
_ = client.DeleteSecret(ctx, vault.ID, "stripe_secret_key")_ = client.DeleteSecretVault(ctx, vault.ID)const vault = await client.createSecretVault({ name: 'stripe-prod' });
await client.putSecret(vault.id, 'stripe_secret_key', 'sk_live_...');const redacted = await client.listSecrets(vault.id);
await client.deleteSecret(vault.id, 'stripe_secret_key');await client.deleteSecretVault(vault.id);Designate the project vault
Section titled “Designate the project vault”Each project picks one vault as its designated source. The LLM
resolver, Brave search, and MCP auth.tokenRef lookups all read
from this vault. Set it via PUT /api/sdk/project/vault (or in the
admin UI’s Secrets page):
curl -X PUT https://api.tavora.ai/api/sdk/project/vault \ -H "X-API-Key: tvr_..." \ -H "Content-Type: application/json" \ -d '{"vault_id":"<vault-id>"}'Pass null to clear the designation; lookups then return
“project has no vault designated” errors at the tool boundary.
Who reads it
Section titled “Who reads it”| Tool | Secret name (convention) |
|---|---|
| LLM provider router (Gemini / OpenAI / OpenRouter / Eden / Ollama) | gemini_api_key, openai_api_key, openrouter_api_key, edenai_api_key, ollama_base_url |
| Brave search primitive | brave_api_key |
| MCP server bearer / header auth | whatever name your agent.jsonc → mcp.auth.tokenRef points at |
Tools that need a secret but find the project has none designated surface a clear error at call time rather than running with a silently empty credential.
Operational notes
Section titled “Operational notes”- Endpoints return
503whenTAVORA_SECRET_KEKis unset on the server. - Self-hosted deployments are responsible for rotating
TAVORA_SECRET_KEKand updating the wrapped DEKs (a re-wrap CLI ships intavora-cli). - The agent’s JS sandbox has no
secret(name)primitive. If you need an agent to drive a credentialed call, expose it via an MCP tool that resolves the secret server-side.