How to Secure Your API Keys for Agent Use
Three credential modes, a storage hierarchy, and honest threat modeling. No "enterprise-grade" theater.
The problem
Your agent needs API keys to do useful work. Send an email through Resend, charge a card through Stripe, create a ticket in Linear — every capability requires a credential.
The default behavior is terrifying: paste the key into a config file, hope nobody reads it.
Most credential advice is written for human developers deploying web apps. Agents are different. They run unattended, make autonomous decisions about which keys to use, and often operate across multiple services in a single workflow. The attack surface is wider and the human oversight is narrower.
This guide covers what actually works.
Three credential modes
There's no single right answer. The right approach depends on how much you trust the infrastructure and how much operational control you want.
Mode 1: Bring Your Own Key (BYOK)
You pass your existing API key to the tool or agent framework. The key stays under your control.
# Environment variable (recommended for servers/CI)
export STRIPE_API_KEY=sk_live_...
# MCP server config (Claude Desktop example)
{
"mcpServers": {
"rhumb": {
"command": "npx",
"args": ["rhumb-mcp"],
"env": {
"RHUMB_API_KEY": "rhumb_live_..."
}
}
}
}
When to use it: You already have accounts with the services you need. You want full control over credentials and billing. You're comfortable managing key rotation.
Security posture: The key is only as safe as where you store it. OS keychain > environment variable > config file > hardcoded string.
Mode 2: Managed capabilities
Rhumb holds the service credential and delivers the capability. You never touch the underlying API key.
# You call Rhumb. Rhumb calls the service.
curl -X POST https://api.rhumb.dev/v1/capabilities/email.send/execute \
-H "X-Rhumb-Key: rhumb_live_..." \
-d '{"to": "user@example.com", "subject": "Hello"}'
When to use it: You don't want to manage individual service accounts. You want Rhumb to handle authentication, rate limits, and failover. You're okay with Rhumb's 20% markup on upstream cost.
Security posture: You trust Rhumb with the service credential. You don't need to store or rotate individual service keys. Your Rhumb API key is the only credential to protect.
Mode 3: x402 anonymous payment
No account. No key. The on-chain payment is the authentication.
# First call: get payment instructions
curl -X POST https://api.rhumb.dev/v1/capabilities/email.send/execute
# Returns 402 with USDC payment details
# After paying on-chain:
curl -X POST https://api.rhumb.dev/v1/capabilities/email.send/execute \
-H "X-Payment: {tx_hash, network: base}"
When to use it: Your agent has a crypto wallet. You want zero-signup, zero-credential execution. You're building autonomous agents that need to operate without human provisioning.
Security posture: No credential to steal. The wallet's private key is the only secret, and it stays on the agent's machine. Replay protection via unique transaction hashes.
Credential storage hierarchy
Not all storage is equal. Here's the ranking from most to least secure:
| Storage | Security | When to use |
|---|---|---|
| OS keychain (macOS Keychain, Windows Credential Manager) | ★★★★★ | Desktop agents, local development |
| Secret manager (1Password, HashiCorp Vault, AWS Secrets Manager) | ★★★★★ | Teams, production, enterprise |
| Environment variables | ★★★★ | Servers, CI/CD, containers |
| Encrypted config file | ★★★ | Offline agents, air-gapped systems |
| Plaintext config file | ★★ | Last resort. Temporary only. |
| Hardcoded in source | ★ | Never. Not even in private repos. |
OS keychain example (macOS)
# Store
security add-generic-password -a "rhumb" -s "RHUMB_API_KEY" -w "rhumb_live_..."
# Retrieve at runtime
RHUMB_API_KEY=$(security find-generic-password -a "rhumb" -s "RHUMB_API_KEY" -w)
Environment variable example (Docker)
# Don't bake keys into images. Pass at runtime.
docker run -e RHUMB_API_KEY=rhumb_live_... my-agent
What we protect against (and what we don't)
Honest security requires honest threat modeling.
Rhumb protects against:- Credential exposure in logs and prompts — keys are injected at the HTTP layer, never surfaced in agent conversation history
- Replay attacks on x402 payments — unique transaction hash constraint
- Rate limit abuse per wallet (x402) or per API key (registered)
- Accidental credential leakage in tool outputs — response sanitization strips auth headers
- A compromised machine — if an attacker has root access, all credentials on that machine are exposed regardless of storage method
- Malicious agent code — if the agent framework itself is compromised, it can read any credential the agent has access to
- Social engineering — if someone tricks you into sharing your API key, that's outside Rhumb's control
We don't use phrases like "enterprise-grade security" or "bank-level encryption" because they don't mean anything specific. We tell you exactly what the boundaries are.
Best practices checklist
.env files with .gitignore, or better yet, use a secret manager reference.{
"rhumb_api_key": "op://Shared/Rhumb/credential"
}
The bottom line
The safest credential is the one that doesn't exist. x402 payments eliminate credentials entirely. Managed capabilities reduce your credential surface to a single Rhumb API key. BYOK gives you full control when you need it.
Pick the mode that matches your trust model. Store credentials in the highest-security option available. Be specific about what you're protecting against.
Your agents are only as secure as their weakest credential.