Secrets Management
Secrets Management
OpenClaw’s configuration file (openclaw.json) supports ${VAR} references that resolve from ~/.openclaw/.env at runtime. This keeps secrets out of git while maintaining a version-controlled config.
How It Works
OpenClaw supports two complementary systems for managing secrets:
1. Environment Variable Templates (${VAR})
config/openclaw.json ~/.openclaw/.env───────────────────── ─────────────────"token": "${OPENCLAW_GATEWAY_TOKEN}" OPENCLAW_GATEWAY_TOKEN=..."botToken": "${TELEGRAM_BOT_TOKEN}" TELEGRAM_BOT_TOKEN=123456:abc...At gateway startup, OpenClaw reads ~/.openclaw/.env and substitutes ${VAR} references in the config. The repo config never contains actual secrets.
2. Secret Refs (v2026.2.15+)
For auth profiles and supported fields, OpenClaw can resolve secrets from external sources at runtime using structured keyRef/tokenRef objects instead of plaintext values.
Three provider types are supported:
| Provider | Source | Example |
|---|---|---|
env | Environment variables | { "source": "env", "id": "OPENAI_API_KEY" } |
file | JSON file with pointer navigation | { "source": "file", "provider": "secrets", "id": "/auth/anthropic/apiKey" } |
exec | External binary (1Password, Vault, sops) | { "source": "exec", "provider": "op", "id": "..." } |
Configure providers in openclaw.json:
"secrets": { "providers": { "secrets": { "source": "file", "path": "~/.openclaw/secrets.json", "mode": "json" } }, "defaults": { "file": "secrets" }}Then use refs in auth-profiles.json instead of plaintext keys:
{ "openai:api-key-backup": { "type": "api_key", "provider": "openai", "keyRef": { "source": "file", "provider": "secrets", "id": "/auth/openai/apiKey" } }}Supported fields: As of 2026-04-05, file-source SecretRefs are the preferred pattern across the config. Confirmed migrated fields on this install include auth-profiles.json (keyRef, tokenRef), models.providers.<p>.apiKey, skill apiKey fields (skills.entries.openai-whisper-api.apiKey, skills.entries.sag.apiKey), plugin config fields (plugins.entries.openclaw-parcel.config.apiKey, plugins.entries.travel-hub.config.token, plugins.entries.porsche-connect-cli.config.porscheApiKey, plugins.entries.brave.config.webSearch.apiKey), tool fields (tools.web.search.apiKey), and the talk.apiKey field for ElevenLabs TTS. The plugin manifest must declare an oneOf: [string, SecretRef] union for any field intended to accept SecretRefs — openclaw-parcel is the reference implementation at ~/GitHub/openclaw-parcel/openclaw.plugin.json. Env vars are still the right choice for process-scoped values that don’t flow through plugin configs: OPENCLAW_GATEWAY_TOKEN, OPENCLAW_HOOKS_TOKEN, TELEGRAM_BOT_TOKEN. The current iMessage path uses imsg plus channels.imessage.cliPath, so it does not need the retired bridge’s shared credential or callback endpoint.
Environment Variables
All required variables are documented in config/.env.example. Only a small set of process-scoped tokens still live in .env — most model/plugin keys have moved to ~/.openclaw/secrets.json via SecretRefs (see Secret Refs).
| Variable | Used By | How to Get It |
|---|---|---|
OPENCLAW_GATEWAY_TOKEN | Gateway HTTP auth | Generate any strong random string |
OPENCLAW_HOOKS_TOKEN | Signing/verifying incoming webhooks (HomeClaw, Travel Hub, location, etc.) | Generate any strong random string |
TELEGRAM_BOT_TOKEN | Exec-approval prompts via Telegram | t.me/BotFather |
Migrated to SecretRefs:
OPENAI_API_KEY,ELEVENLABS_API_KEY,GEMINI_API_KEY, the Anthropic key, Travel Hub token, Porsche Connect key, Brave Search key (if enabled), and Parcel API key now live in~/.openclaw/secrets.json. Do not add new model/plugin keys to.env— use SecretRefs.
Initial Setup
cp config/.env.example ~/.openclaw/.envchmod 600 ~/.openclaw/.env# Edit ~/.openclaw/.env and fill in real valuesAdding a New Secret
Preferred path — file-source SecretRef (as of 2026-04-05):
- Add the secret value to
~/.openclaw/secrets.jsonat a JSON pointer path like/plugins/<plugin>/apiKey - Set the field in
openclaw.jsonviaopenclaw config set <path> --ref-source file --ref-provider secrets --ref-id /plugins/<plugin>/apiKey(the ref-builder flags produce the correct{source, provider, id}object; raw JSON edits are error-prone) - Sync the repo copy:
cp ~/.openclaw/openclaw.json config/openclaw.json - Restart the gateway:
openclaw gateway restart - Verify with
bash scripts/smoke-test-plugins.sh— expected10 passed, 0 failed
Fallback path — environment variable (only for values that don’t flow through plugin configs, like the gateway token or channel passwords):
- Add
${NEW_VAR}to the appropriate field inconfig/openclaw.json - Add
NEW_VAR=actual-valueto~/.openclaw/.env - Add
NEW_VAR=your-placeholdertoconfig/.env.example(with a comment explaining where to get it) - Copy the updated config:
cp config/openclaw.json ~/.openclaw/openclaw.json - Restart the gateway:
openclaw gateway restart
Secrets Audit (secrets-audit.sh)
The scripts/secrets-audit.sh script verifies the entire secrets chain is intact. Run it anytime you change config or rotate tokens.
bash scripts/secrets-audit.shWhat It Checks
| Check | What It Verifies |
|---|---|
| 1. Hardcoded secrets | No apiKey/password/token/secret fields in config/openclaw.json have literal values (all should use ${VAR}) |
| 2. Runtime config drift | ~/.openclaw/openclaw.json matches config/openclaw.json — no sections added directly to runtime that are missing from the repo |
| 3. Env var resolution | Every ${VAR} in the config has a matching non-placeholder value in ~/.openclaw/.env, and OpenClaw resolves it correctly |
| 4. .env.example coverage | Every ${VAR} reference is documented in config/.env.example |
| 5. Git tracked files | No plaintext secrets leaked into any git-tracked file (scans first 12 chars of each secret value) |
| 6. File permissions | ~/.openclaw/.env (600), ~/.config/fastmail-cli/config.json (600), ~/.config/gh/hosts.yml (600) |
| 7. CLI-managed auth | Fastmail CLI token is authenticated and not expiring soon |
Reading the Output
🦞 Lobster Secrets Audit========================
1. Hardcoded secrets in config/openclaw.json ✓ No hardcoded secrets found
2. Runtime config drift ✓ No hardcoded secrets in runtime config
3. Env var resolution ✓ BRAVE_API_KEY — set and resolves correctly ⚠ GEMINI_API_KEY — placeholder value (not yet configured)
4. .env.example coverage ✓ BRAVE_API_KEY — documented
5. Tracked files (plaintext secret scan) ✓ No known secrets in tracked files
6. File permissions ✓ ~/.openclaw/.env — 600 (owner-only)
7. CLI-managed auth ✓ Fastmail CLI — authenticated (45 days left)
========================1 warning(s), 0 errors- Green checkmark — check passed
- Yellow warning — non-critical issue (placeholder values, missing optional files)
- Red X — critical issue that needs fixing (hardcoded secrets, missing env vars, leaked secrets)
Each failure includes a hint with the exact fix command.
Security Audit Integration
The broader openclaw-agents/lobster/scripts/security-audit.sh calls secrets-audit.sh as part of a comprehensive security check that also validates:
- Exec approval policies (deny-by-default, per-agent allowlists)
- Agent tool policies (restricted agents can’t access sensitive tools)
- Skill isolation (apple-mail only in lobster workspace)
- Travel-hub wrapper validation (ALLOWED_TOOLS check)
bash openclaw-agents/lobster/scripts/security-audit.shToken Rotation
Fastmail CLI
The Fastmail CLI token expires periodically. The secrets audit warns when expiry is within 7 days.
fastmail auth # Re-authenticate (opens browser)fastmail auth status # Check expiryToken cached at ~/.config/fastmail-cli/config.json (should be 600 permissions).
Travel Hub Token
Travel Hub is loaded as an OpenClaw plugin; its Bearer token lives in ~/.openclaw/secrets.json at JSON pointer /plugins/travel-hub/token and is wired into the plugin via a SecretRef at plugins.entries.travel-hub.config.token (migrated 2026-04-05).
To rotate:
- Visit
https://travel-hub-mcp.shahine.com/get-tokenin a browser - Authenticate via Cloudflare Access SSO
- Copy the new Bearer token
- Edit
~/.openclaw/secrets.jsonand set/plugins/travel-hub/tokento the new value (the secrets provider does not supportopenclaw config setwrites) openclaw gateway restart— plugin config changes need a full restart to re-register- Verify with
bash scripts/smoke-test-plugins.sh— look for thetravel_hub_tripstool call succeeding
Gateway Token
The OPENCLAW_GATEWAY_TOKEN authenticates local connections to the gateway. To rotate:
- Generate a new random string
- Update
OPENCLAW_GATEWAY_TOKENin~/.openclaw/.env - Restart the gateway:
openclaw gateway restart - Update any remote clients (iOS app, Tailscale Serve consumers)
Anthropic API Key
With secret refs configured, the Anthropic API key lives in ~/.openclaw/secrets.json and is referenced via keyRef in each agent’s auth-profiles.json. To rotate:
- Get a new key from console.anthropic.com/settings/keys
- Update the value in
~/.openclaw/secrets.jsonat/auth/anthropic/apiKey - Reload secrets:
openclaw secrets reload
Without secret refs, use the interactive flow:
openclaw models auth login --provider anthropicRemember to update auth for all agents — each has its own auth-profiles.json.
Secrets Audit (Built-in)
OpenClaw v2026.2.15+ includes a built-in secrets audit:
openclaw secrets audit # Show all findingsopenclaw secrets audit --check # Exit non-zero on findingsThis scans for plaintext keys in auth profiles, config files, and .env, reporting unresolved refs and shadowed values. Use the interactive wizard to migrate:
openclaw secrets configure # Interactive setupopenclaw secrets apply --from /tmp/plan.json # Apply migration planopenclaw secrets reload # Reload runtime secrets