Primitive/vault3 min read

Introducing /vault: per-user encrypted storage for agent secrets

The vault primitive: per-user encrypted storage for the secrets your agents hold — API keys, cookies, tokens — envelope-encrypted with a managed KMS.

Vault primitive →Read the docs →

Primitive/vault
TL;DR
  • /vault per-user encrypted key/value storage for the secrets an agent generates or holds (formerly /credentials)
  • Scoped per tenant user each value is bound to one user, so one customer's secrets are never visible to another
  • Envelope-encrypted with a managed KMS values are encrypted at rest and revealed only through a POST, never in a URL
  • Lockable entries store a secret an agent must use but can never read back
  • Expiring and rotatable set an expiry, and re-wrap or fully re-encrypt a value with rotate
  • Composes with /browser (autonomous signup vaults the password) and /connections for a unified per-user credential view

Give an agent the ability to act in the real world and you immediately have a secrets problem: the API keys it generates, the cookies it collects, the tokens it is handed all have to live somewhere safe. Naïve is the autonomous company infrastructure that gives agents real-world capabilities, and the /vault primitive — the Vault (formerly /credentials) — is where those per-user secrets belong: envelope-encrypted, scoped to one user, and revealed only through a deliberate call. It is the locked drawer under the rest of the runtime.

What the Vault stores

The Vault holds the secrets an agent encounters that aren't third-party OAuth grants (those live in connections): a SaaS API key the agent generated during signup, a session cookie, a KYC reference. Each value is envelope-encrypted with a managed KMS and scoped to one tenant user.

naive vault put instantly.api_key key_xyz --user alice --kind api_key
naive vault reveal instantly.api_key --user alice
naive vault list --user alice

Entries carry a kindapi_key, password, cookie, token, note, or reference — so the same store handles every shape of secret an agent runs into.

Store, reveal, and lock

put is idempotent on the key, so re-storing simply replaces the value. reveal is a POST, which matters: the secret travels in the response body, never in a URL or an access log.

await naive.forUser(alice.id).vault.put("instantly.api_key", "key_xyz", { kind: "api_key" });
const { value } = await naive.forUser(alice.id).vault.reveal("instantly.api_key");

The strongest custody control is the locked entry. A locked value can be stored and used indirectly but never revealed back to the agent. This is how autonomous /browser signup works safely: the generated password is written to the Vault, used to fill a form, and never handed to the agent or the model.

Expiring and rotating

Two controls keep long-lived secrets from becoming long-lived liabilities:

  • expires_at — set an ISO timestamp and the entry drops out of listings and returns not-found on reveal once it passes, so a short-lived token cleans itself up.
  • rotate — re-wrap the data key cheaply, or fully re-encrypt the stored value when you want a clean cryptographic reset.
# Periodically re-wrap the key that protects a stored secret
naive vault rotate instantly.api_key --user alice

Isolated per user, unified in view

Every entry is bound to a single tenant user, so one customer's secrets are never listed or revealed to another — isolation is a property of the runtime, not something your application has to enforce. In the dashboard, a user's connections surface read-only alongside their Vault entries, giving you one per-user view of everything that user's agents can authenticate with.

What you can build

Let agents keep the keys they create — When an agent signs up for a service and generates an API key, store it in that user's Vault under a stable name and reveal it only when a call needs it.

Hold secrets an agent must use but never see — Lock a password or token so the agent can act with it — filling a form, authenticating a call — without ever being able to read the raw value into its context.

Give every tenant an isolated secret store — In a multi-tenant app, each customer gets their own encrypted namespace, so a prompt-injected agent in one tenant can't reach another tenant's secrets.

Keep long-lived credentials fresh — Combine expires_at and rotate so tokens age out or get re-wrapped on a cadence you control, instead of sitting readable indefinitely.

Get started

Frequently Asked Questions
What is the Vault?+
The Vault (Naïve's /vault primitive, formerly /credentials) is per-user encrypted key/value storage for the secrets an agent encounters that aren't third-party OAuth grants — a SaaS API key it generated, a session cookie, a KYC reference. Each value is envelope-encrypted with a managed KMS and scoped to one tenant user.
How does storing and revealing work?+
Put a value under a key with an optional kind — api_key, password, cookie, token, note, or reference. Put is idempotent on the key. Reveal is a POST, so the secret travels in the response body and never appears in a URL or server log. Listing returns keys with values masked.
Can an agent be blocked from reading a secret back?+
Yes. Mark an entry as locked and it can be stored and used indirectly but never revealed back to the agent. This fits cases where an agent must act with a secret — for example a password filled during autonomous signup — but should never be able to read the raw value.
How are secrets isolated between customers?+
Every entry is scoped to a single tenant user, so one customer's keys are never listed or revealed to another. Values are envelope-encrypted with a managed KMS; the rotate operation re-wraps the data key cheaply, and regenerating the data-encryption key fully re-encrypts the stored value.
How does the Vault relate to connections?+
Connections (the /connections primitive) hold third-party OAuth grants; the Vault holds the other secrets an agent generates or is given. In the dashboard both surface together in one per-user credential view, so you can see everything a given end-user's agents can authenticate with in a single place.
Do entries expire?+
You can set an expires_at timestamp on any entry. Expired entries are excluded from listings and return not-found on reveal, so a short-lived token cleans itself up. Combine expiry with rotate to keep long-lived secrets fresh without leaving stale values readable.
How do I get started?+
Run naive vault put instantly.api_key key_xyz --user alice --kind api_key, read it back with naive vault reveal instantly.api_key --user alice, and list with naive vault list --user alice. The full guide is at usenaive.ai/docs/getting-started/vault.
DZ
Dennis ZaxCTO

CTO of Naïve. Building the open-source agent runtime.

@denniszax
Keep reading