Credential Vault
The credential vault provides encrypted storage for external service credentials (GitHub, AWS, Slack, etc.). Credentials are encrypted with a key derived from the agent’s Ed25519 private key — only that specific agent instance can decrypt its own vault.
Why a Vault
AI agents need credentials to interact with external services. Without a vault, humans end up pasting API keys into chat, hardcoding secrets in configs, or giving agents unrestricted access. The vault solves this:
- Store once, use forever — Human provides the credential once; the agent retrieves it in any future session
- Encrypted at rest — AES-256-GCM encryption, key never leaves the agent’s machine
- Agent-scoped — Only the agent that stored the credential can decrypt it
- Irrecoverable by design — If the agent’s keypair is deleted, the credentials are gone
Encryption Model
Agent's Ed25519 private key (PKCS8 DER)
│
▼ HKDF-SHA256 (salt: "agent-id-vault-v1", info: "vault-encryption")
│
▼ 256-bit symmetric key
│
▼ AES-256-GCM (random 96-bit IV per credential)
│
▼ Ciphertext + 128-bit authentication tag
│
▼ Stored as JSON: { iv, data, tag } (hex-encoded, mode 0600)Storing Credentials
There are three secure methods to provide credentials to the vault, listed from most to least secure:
Option A: From File (Most Secure)
The secret never appears on the command line or in chat logs:
echo 'ghp_xxx' > /tmp/tok && chmod 600 /tmp/tok
node cli.mjs vault-store --service github --type api-key --credential-file /tmp/tok
rm /tmp/tokOption B: From Environment Variable
export GITHUB_TOKEN=ghp_xxx
node cli.mjs vault-store --service github --type api-key --credential-env GITHUB_TOKENOption C: Via Stdin Pipe
echo 'ghp_xxx' | node cli.mjs vault-store --service github --type api-keySecurity Comparison
| Method | Secret in ps? | In shell history? | In chat log? |
|---|---|---|---|
--credential-file | No | No | No |
--credential-env | No | Depends on shell | No |
| stdin pipe | No | The echo line, yes | No |
--credential flag | Yes | Yes | No |
| Paste in chat | No | No | Yes |
Prefer --credential-file or --credential-env. The --credential flag puts the secret in the process argument list, visible via ps.
Credential Types
Use --type to tag what kind of credential it is:
| Type | Description | Notes |
|---|---|---|
api-key | API key / personal access token | Default |
password | Username + password pair | Use with --username |
oauth | OAuth access/refresh token | |
bearer | Bearer token | |
custom | Anything else |
Store Examples
# GitHub personal access token (from file)
echo 'ghp_abc123' > /tmp/cred && chmod 600 /tmp/cred
node cli.mjs vault-store --service github --type api-key --credential-file /tmp/cred
rm /tmp/cred
# AWS credentials (from env)
node cli.mjs vault-store --service aws --type api-key \
--credential-env AWS_SECRET_ACCESS_KEY \
--username "$AWS_ACCESS_KEY_ID" \
--url "https://aws.amazon.com"
# Service with username + password (piped)
echo 'mypassword' | node cli.mjs vault-store --service docker-hub \
--type password --username "myuser" --url "https://hub.docker.com"
# OAuth token
node cli.mjs vault-store --service slack --type oauth --credential-env SLACK_BOT_TOKENRetrieving Credentials
node cli.mjs vault-get --service githubReturns:
{
"ok": true,
"service": "github",
"type": "api-key",
"credential": "ghp_xxx..."
}Use the credential value in API calls:
TOKEN=$(node cli.mjs vault-get --service github | jq -r .credential)
curl -H "Authorization: Bearer $TOKEN" https://api.github.com/userThe credential is decrypted in memory and never written to disk in plaintext.
Listing Credentials
node cli.mjs vault-listReturns a list of services with metadata (type, URL, username) without decrypting the credential values.
Removing Credentials
node cli.mjs vault-remove --service githubUpdating Credentials
Run vault-store again with the same --service name. The existing credential is replaced; the original creation timestamp is preserved.
Next Steps
- External Services Auth — Use vault credentials with external services
- CLI Reference — Full vault command reference