Skip to content

Credential vault

The vault holds the underlying credentials your agents use (Stripe key, database password, OAuth token, anything). Operators store them once. Agents request short-lived leases at the moment they need them.

Long-lived static secrets in an agent’s environment are a problem for three reasons:

  1. They survive agent suspension. Killing the agent’s JWT doesn’t kill the API key that’s already cached in its process.
  2. They’re hard to rotate. Every change requires redeploying every agent.
  3. They have no audit. You can’t tell from the logs which agent used the key when.

Vault leases solve all three. The lease has an expires_at; revoking it is one API call; every issue and every revoke writes an audit event.

BackendWhere the bytes actually livePicked by
staticcredentials Postgres table, encrypted with AES-256-GCM (root key from AGENTUM_ENCRYPTION_KEY_HEX)default (no env var)
hashicorpHashiCorp Vault KV v2 mountAGENTUM__VAULT_BACKEND=hashicorp
awsAWS Secrets ManagerAGENTUM__VAULT_BACKEND=aws
azureAzure Key VaultAGENTUM__VAULT_BACKEND=azure

Configuration for each backend is in .env.

  1. Store the underlying credential (operator action, one-time):

    Terminal window
    # Read the secret from an env var so it doesn't show up in shell history
    STRIPE_KEY="sk_live_..." \
    agentum vault store \
    --agent-id <uuid> \
    --service-name stripe \
    --from-env STRIPE_KEY \
    --cred-type api_key

    Or pipe it from stdin:

    Terminal window
    printf '%s' "$STRIPE_KEY" | agentum vault store \
    --agent-id <uuid> \
    --service-name stripe

    Response includes the cred_id. The plaintext is now encrypted in Postgres and never returns from this endpoint again.

  2. Issue a lease (agent or operator on its behalf):

    Terminal window
    agentum vault issue --agent-id <uuid> --service-name stripe

    Response:

    {
    "lease_id": "2948e177-b327-448e-a746-b20161b3b444",
    "value": "sk_live_...",
    "expires_at": "2026-05-13T19:05:32.084569451Z",
    "credential_type": "api_key",
    "header_name": "X-Api-Key",
    "backend": "static"
    }

    The value is delivered once. If you lose it, issue a new lease.

  3. Use the credential. Two patterns:

    • Pass it directly. The agent puts the value in whatever HTTP client it uses. Simple, but the secret lives in the agent’s process for the lease duration.
    • Placeholder injection (proxy path only). The agent puts Authorization: Bearer agentum://stripe-key in its outbound headers. Lupid’s HTTPS gateway sees the agentum:// marker and substitutes the real secret before the request leaves. The agent’s process never sees plaintext.
  4. Revoke immediately when the agent is done with it (or compromised):

    Terminal window
    agentum vault revoke <lease-id>

    Or revoke every active lease for an agent in one shot (e.g. on suspension):

    Terminal window
    curl -X POST http://localhost:3000/api/v1/vault/revoke-agent/<uuid> \
    -H "X-API-Key: $LUPID_API_KEY"

    Leases also auto-expire at expires_at; the background lease-tracker reaps them.

Terminal window
# Active leases for one agent
agentum vault leases --agent-id <uuid>
# All active leases
agentum vault leases
# Pretty-print with table output
agentum --output table vault leases

The dashboard’s /vault page shows the same data with a health strip (active vs expiring-in-1-hour vs revoked-today), per-credential rail, and live lease feed over SSE.

There’s a Playwright test that exercises the whole pipeline against the live stack end to end — vault-live-flow.spec.ts. Useful as a reference for the expected UI flow if you’re building your own integration.