Agent Secret Store DocsSign up
🔑 Concepts

Vault Storage

How secrets are organized, classified, versioned, and managed — from simple API keys to complex multi-environment credential stores.

Namespaces

Every secret lives at a path — a forward-slash delimited string that forms the namespace hierarchy. Paths are arbitrary: you define the structure that makes sense for your project.

The most common pattern is environment/service/key-name — this maps naturally to scoped token patterns like secrets:read:production/openai/*.

Shell
# Flat namespace (simple projects)
openai-key
stripe-webhook
github-token

# Hierarchical namespaces (recommended for production)
production/openai/api-key
production/stripe/secret-key
production/stripe/webhook-secret
production/postgres/connection-string

# Multi-environment pattern
staging/openai/api-key
staging/stripe/secret-key

# Service-scoped namespaces
payments-service/stripe/secret-key
payments-service/stripe/webhook-secret
auth-service/google/client-secret
auth-service/jwt/signing-key

# Agent-scoped namespaces
agents/summarizer/openai-key
agents/researcher/tavily-key
agents/researcher/openai-key

Namespace tips

Use the environment as the top-level prefix (production/, staging/,development/). This lets you write scoped tokens that are strictly isolated per environment — a staging agent cannot accidentally read production secrets.

Secret types

The type field classifies a secret's nature. It is used for display, filtering, audit enrichment, and rotation-handler routing — not for access control.

TypeValueExamples
🔑api_keyOpenAI, Anthropic, Tavily, Replicate, Pinecone API keys
🔄oauth_tokenGitHub OAuth, Google refresh tokens, Slack bot tokens
🗄️db_credentialPostgreSQL, MySQL, MongoDB, Redis connection strings
🔐ssh_keyPrivate SSH keys for server access or git operations
💳payment_credentialStripe secret key, PayPal API credentials, Coinbase
📦customAnything else — JWT signing keys, webhook secrets, etc.

Access tiers

The access tier controls whether a token request for that secret requires human approval. Assign tiers based on the blast radius if the credential were compromised.

standard✅ No approval required

Low-risk credentials. Token requests are fulfilled instantly.

Examples: Read-only API keys, public data sources, sandbox/dev keys, logging service tokens, non-sensitive webhook secrets.

sensitive⚠️ Approval required (configurable)

Elevated risk. Approval can be required or waived per-token request.

Examples: Production API keys with write access, OAuth tokens, staging database connections, internal service-to-service credentials.

critical🚨 Approval always required

Maximum protection. Every token request requires explicit approval.

Examples: Production database connection strings, payment processor secret keys, SSH private keys, root/admin credentials, KMS keys.

Default to sensitive, not standard

When in doubt, use sensitive. It's easy to relax a tier later — it's much harder to audit all the unapproved accesses after the fact.

Creating secrets

Python

provision_secrets.py
from agentsecretstore import AgentVault, SecretType, AccessTier

async def provision_secrets():
    async with AgentVault() as vault:
        # API key — standard tier, auto-expires in 90 days
        await vault.create_secret(
            path="production/openai/api-key",
            value="sk-proj-...",
            type=SecretType.API_KEY,
            tier=AccessTier.STANDARD,
            tags={"service": "openai", "team": "ml-platform"},
            expires_in_days=90,
        )

        # Database credential — critical tier, requires approval
        await vault.create_secret(
            path="production/postgres/main",
            value="postgresql://user:pass@host:5432/db",
            type=SecretType.DB_CREDENTIAL,
            tier=AccessTier.CRITICAL,
            tags={"service": "postgres", "env": "production"},
            description="Main production PostgreSQL connection string",
        )

        # OAuth token — sensitive tier, expires naturally
        await vault.create_secret(
            path="production/github/oauth-token",
            value="ghp_xxxx...",
            type=SecretType.OAUTH_TOKEN,
            tier=AccessTier.SENSITIVE,
            tags={"provider": "github", "scopes": "repo,read:org"},
        )

TypeScript

provisionSecrets.ts
import { AgentVault, SecretType, AccessTier } from '@agentsecretstore/sdk';

const vault = new AgentVault();

await vault.createSecret({
  path: 'production/openai/api-key',
  value: 'sk-proj-...',
  type: SecretType.API_KEY,
  tier: AccessTier.STANDARD,
  tags: { service: 'openai', team: 'ml-platform' },
  expiresInDays: 90,
});

Secret versioning

Every time you update a secret, the old value is preserved as a prior version. Versions are immutable after creation. You can list all versions, fetch a specific historical value, and roll back the active version at any time.

versioning.py
from agentsecretstore import AgentVault

async def rotate_and_rollback():
    async with AgentVault() as vault:
        # Get current version
        secret = await vault.get_secret("production/openai/api-key")
        print(f"Current version: {secret.version}")  # e.g. v3

        # Update creates a new version automatically
        await vault.update_secret(
            path="production/openai/api-key",
            value="sk-proj-new-key...",
        )

        # List all versions
        versions = await vault.list_versions("production/openai/api-key")
        for v in versions:
            print(f"  {v.version}: created {v.created_at}, active={v.is_active}")

        # Rollback to previous version
        await vault.rollback_secret(
            path="production/openai/api-key",
            version="v2",          # Roll back to specific version
        )

        # Get a specific historical version
        old_secret = await vault.get_secret(
            path="production/openai/api-key",
            version="v1",
        )

Versions are stored encrypted

Each version uses its own envelope-encrypted DEK. Rolling back restores the previous DEK + ciphertext — the plaintext value at that version is never re-stored. Version history is retained for 90 days (Growth) or 365 days (Enterprise).

Metadata and tags

Every secret can carry arbitrary key-value tags and a human-readable description. Tags are indexed and searchable — useful for filtering secrets by environment, team, or service in the dashboard and API.

FieldTypeDescription
descriptionstringFree-text note shown in the dashboard and audit log
tagsobjectArbitrary key-value pairs; e.g. { team: "platform", env: "prod" }
created_bystringActor ID of the principal that created the secret (auto-set)
created_attimestampISO-8601 creation time (auto-set)
updated_attimestampISO-8601 last update time (auto-set)
versionstringCurrent active version identifier (e.g. "v3")
expires_attimestamp | nullOptional expiration time; null = never expires

.env bulk import

Migrating from .env files? The CLI and SDK can parse a standard .env file and create vault secrets in bulk, preserving the variable names as path suffixes.

CLI

Shell
# Method 1: Import directly from .env file
ass import .env --namespace production --tier standard

# Method 2: Pipe from stdin
cat .env | ass import --namespace staging

# Method 3: With tier overrides per prefix
ass import .env \
  --namespace production \
  --tier-prefix "DB_=critical" \
  --tier-prefix "STRIPE_=sensitive" \
  --tier-prefix "OPENAI_=standard"

# Preview without writing (dry run)
ass import .env --namespace production --dry-run

Python SDK

import_env.py
from agentsecretstore import AgentVault

async def import_env_file(env_path: str, namespace: str):
    """Import a .env file into the vault under a namespace."""
    async with AgentVault() as vault:
        result = await vault.import_env(
            path=env_path,
            namespace=namespace,
            tier_map={
                "DB_": "critical",
                "STRIPE_": "sensitive",
                "OPENAI_": "standard",
            },
            dry_run=False,
        )
    print(f"Imported {result.created} secrets, skipped {result.skipped}")
    for secret in result.secrets:
        print(f"  {secret.path} ({secret.tier})")

Idempotent imports

Re-running the import on the same file will skip secrets that already exist at the same path. Use --overwrite (CLI) or overwrite=True (SDK) to force updates.

Expiration policies

Set an expires_at timestamp on any secret. Once expired, the vault refuses to serve the secret value — agents receive a 410 Gone response. Expiration does not delete the secret; it can be extended or renewed.

Dashboard alerts and webhook notifications fire 7 days and 1 day before expiration, giving your team time to rotate before agents start failing.

expiration.py
from agentsecretstore import AgentVault
from datetime import datetime, timezone, timedelta

async def set_expiration_policies():
    async with AgentVault() as vault:
        # Expire in 30 days
        await vault.update_secret(
            path="production/github/deploy-token",
            expires_at=datetime.now(timezone.utc) + timedelta(days=30),
        )

        # Expire at a specific date (e.g., OAuth token expiry)
        await vault.update_secret(
            path="production/google/refresh-token",
            expires_at=datetime(2025, 12, 31, 23, 59, 59, tzinfo=timezone.utc),
        )

        # Clear expiration (make permanent)
        await vault.update_secret(
            path="production/stripe/restricted-key",
            expires_at=None,
        )

Scoped Tokens

Issue least-privilege tokens that cover specific namespace paths.

Secret Rotation

Set up scheduled and automated secret rotation.

Audit Trail

Track every read, write, and token issuance against your secrets.

.env Migration Guide

Step-by-step walkthrough for migrating from .env files.