Secret vaults
A secret vault is an app-scoped, envelope-encrypted bucket of
named credentials. Each app 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 app vault
Section titled “Designate the app vault”Each app 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/app/vault (or in the
admin UI’s Secrets page):
curl -X PUT https://api.tavora.ai/api/sdk/app/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
“app 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 app 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-tools). - 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.