Skip to content

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:

ProviderSourceExample
envEnvironment variables{ "source": "env", "id": "OPENAI_API_KEY" }
fileJSON file with pointer navigation{ "source": "file", "provider": "secrets", "id": "/auth/anthropic/apiKey" }
execExternal 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).

VariableUsed ByHow to Get It
OPENCLAW_GATEWAY_TOKENGateway HTTP authGenerate any strong random string
OPENCLAW_HOOKS_TOKENSigning/verifying incoming webhooks (HomeClaw, Travel Hub, location, etc.)Generate any strong random string
TELEGRAM_BOT_TOKENExec-approval prompts via Telegramt.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

Terminal window
cp config/.env.example ~/.openclaw/.env
chmod 600 ~/.openclaw/.env
# Edit ~/.openclaw/.env and fill in real values

Adding a New Secret

Preferred path — file-source SecretRef (as of 2026-04-05):

  1. Add the secret value to ~/.openclaw/secrets.json at a JSON pointer path like /plugins/<plugin>/apiKey
  2. Set the field in openclaw.json via openclaw 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)
  3. Sync the repo copy: cp ~/.openclaw/openclaw.json config/openclaw.json
  4. Restart the gateway: openclaw gateway restart
  5. Verify with bash scripts/smoke-test-plugins.sh — expected 10 passed, 0 failed

Fallback path — environment variable (only for values that don’t flow through plugin configs, like the gateway token or channel passwords):

  1. Add ${NEW_VAR} to the appropriate field in config/openclaw.json
  2. Add NEW_VAR=actual-value to ~/.openclaw/.env
  3. Add NEW_VAR=your-placeholder to config/.env.example (with a comment explaining where to get it)
  4. Copy the updated config: cp config/openclaw.json ~/.openclaw/openclaw.json
  5. 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.

Terminal window
bash scripts/secrets-audit.sh

What It Checks

CheckWhat It Verifies
1. Hardcoded secretsNo 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 resolutionEvery ${VAR} in the config has a matching non-placeholder value in ~/.openclaw/.env, and OpenClaw resolves it correctly
4. .env.example coverageEvery ${VAR} reference is documented in config/.env.example
5. Git tracked filesNo 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 authFastmail 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)
Terminal window
bash openclaw-agents/lobster/scripts/security-audit.sh

Token Rotation

Fastmail CLI

The Fastmail CLI token expires periodically. The secrets audit warns when expiry is within 7 days.

Terminal window
fastmail auth # Re-authenticate (opens browser)
fastmail auth status # Check expiry

Token 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:

  1. Visit https://travel-hub-mcp.shahine.com/get-token in a browser
  2. Authenticate via Cloudflare Access SSO
  3. Copy the new Bearer token
  4. Edit ~/.openclaw/secrets.json and set /plugins/travel-hub/token to the new value (the secrets provider does not support openclaw config set writes)
  5. openclaw gateway restart — plugin config changes need a full restart to re-register
  6. Verify with bash scripts/smoke-test-plugins.sh — look for the travel_hub_trips tool call succeeding

Gateway Token

The OPENCLAW_GATEWAY_TOKEN authenticates local connections to the gateway. To rotate:

  1. Generate a new random string
  2. Update OPENCLAW_GATEWAY_TOKEN in ~/.openclaw/.env
  3. Restart the gateway: openclaw gateway restart
  4. 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:

  1. Get a new key from console.anthropic.com/settings/keys
  2. Update the value in ~/.openclaw/secrets.json at /auth/anthropic/apiKey
  3. Reload secrets: openclaw secrets reload

Without secret refs, use the interactive flow:

Terminal window
openclaw models auth login --provider anthropic

Remember 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:

Terminal window
openclaw secrets audit # Show all findings
openclaw secrets audit --check # Exit non-zero on findings

This scans for plaintext keys in auth profiles, config files, and .env, reporting unresolved refs and shadowed values. Use the interactive wizard to migrate:

Terminal window
openclaw secrets configure # Interactive setup
openclaw secrets apply --from /tmp/plan.json # Apply migration plan
openclaw secrets reload # Reload runtime secrets