Supabase Vault — Enhanced Secret Storage
Replaces the local secrets.json vault with Supabase Vault. All OpenClaw API keys, tokens, and auth credentials are stored AES-256 encrypted in your Supabase Postgres database. Bootstrap credentials (the Supabase URL + service_role key needed to reach the vault) are encrypted locally using OS keychain or machine-derived AES-256-GCM.
See references/architecture.md for the full threat model and design rationale.
Prerequisites
- A Supabase project (free tier works). Get one at supabase.com.
- Project URL + service_role key (from Supabase Dashboard → Settings → API).
- Node.js 18+ (already available in OpenClaw's environment).
Installation
Step 1 — Install @supabase/supabase-js
npm install --prefix ~/.openclaw/skills/supabase-vault @supabase/supabase-js
Step 2 — Run setup.sql in Supabase
Open your Supabase project → SQL Editor → paste and run assets/setup.sql.
This creates four wrapper functions (insert_secret, read_secret, delete_secret, list_secret_names) restricted to service_role only.
Verify with:
SELECT proname FROM pg_proc
WHERE proname IN ('insert_secret','read_secret','delete_secret','list_secret_names');
-- Should return 4 rows
Step 3 — Install the gateway RPC handler
Copy assets/rpc-handler.ts to src/gateway/server-methods/supabase-vault.ts in the OpenClaw source, then register it in the server-methods index:
// In src/gateway/server-methods.ts (or equivalent)
import { createSupabaseVaultHandlers } from "./supabase-vault.js";
// ...
Object.assign(handlers, createSupabaseVaultHandlers());
Step 4 — Install the dashboard UI
Copy the UI files to their destinations:
assets/controller.ts → ui/src/ui/controllers/supabase-vault.ts
assets/views.ts → ui/src/ui/views/supabase-vault.ts
Register as an Integrations tab using the plugin architecture (same pattern as pipedream-connect or discord-connect):
// In the plugin registration or plugins-ui.ts:
{
id: "supabase-vault",
label: "Supabase Vault",
icon: "🔐",
section: "integrations",
controller: "supabase-vault",
view: "supabase-vault",
}
Step 5 — Rebuild & restart
cd ~/openclaw && npm run build
(sleep 3 && systemctl --user restart openclaw-gateway) &
Step 6 — Connect via dashboard
Open the Control UI → Integrations → Supabase Vault. Enter your Project URL and service_role key, then click Connect & Test.
Exec Provider Config
After connecting, the skill automatically adds this to ~/.openclaw/openclaw.json:
{
"secrets": {
"providers": {
"supabase": {
"source": "exec",
"command": "node",
"args": ["~/.openclaw/skills/supabase-vault/scripts/fetch-secrets.js"],
"jsonOnly": true,
"trustedDirs": ["~/.openclaw/skills/supabase-vault"],
"timeoutMs": 8000
}
}
}
}
After migrating secrets, SecretRefs in config will point to this provider:
{ "source": "exec", "provider": "supabase", "id": "/OPENAI_API_KEY" }
How It Works
Gateway starts
→ exec provider triggers fetch-secrets.js
→ keychain.js retrieves SUPABASE_URL + SERVICE_ROLE_KEY
(macOS: Keychain Access / Linux: GNOME Keyring / fallback: AES-256-GCM file)
→ @supabase/supabase-js createClient(url, key)
→ supabase.rpc('read_secret', { secret_name }) for each requested key
→ outputs: { protocolVersion: 1, values: { "/KEY": "value" }, errors: {} }
→ OpenClaw runtime snapshot populated — secrets in memory only
Bootstrap Credential Storage by Platform
| Platform | Method | Storage |
|---|---|---|
| macOS | security CLI | Keychain Access (hardware-backed on Apple Silicon) |
| Linux (desktop) | secret-tool | GNOME Keyring / KWallet |
| WSL2 / headless | AES-256-GCM | ~/.openclaw/supabase-vault-config.enc (machine-derived key) |
| Any | AES-256-GCM | Fallback always available |
The AES-256-GCM fallback uses PBKDF2-HMAC-SHA512 (600,000 iterations) with a key derived from /etc/machine-id + $USER + app-salt. The encrypted file is unreadable on any other machine or as any other user.
Migration
From the dashboard: Integrations → Supabase Vault → Migrate from Local Vault.
Or from the CLI:
node ~/.openclaw/skills/supabase-vault/scripts/migrate.js
node ~/.openclaw/skills/supabase-vault/scripts/migrate.js --yes # non-interactive
node ~/.openclaw/skills/supabase-vault/scripts/migrate.js --dry-run # preview only
Migration moves all keys from secrets.json to Supabase Vault and updates all SecretRefs in openclaw.json from file → exec/supabase. The local secrets.json is left in place as a safety backup.
Security Notes
- Vault secrets: AES-256 encrypted at rest via libsodium. Encryption key never in DB — database dumps are useless without it.
- Bootstrap creds: Encrypted via OS keychain or AES-256-GCM with machine-derived key. Not readable on another machine.
- Service_role key: Bypasses Supabase RLS — keep this project dedicated to OpenClaw secrets only.
- Memory only at runtime: No decrypted values on disk. Secrets in RAM during gateway session only.
- exec provider security: OpenClaw validates
trustedDirsand file permissions onfetch-secrets.jsbefore execution.