Secret Vault
AES-256-GCM encrypted key-value store. Secrets are encrypted at rest using a 32-byte master key. Plaintext is decrypted in-memory only, never returned via API, and never stored in application databases.
Two Scopes
| Scope | Namespace | Purpose |
|---|---|---|
| App secrets | Per appId |
Scoped to a specific Application. Injected as env vars when the backend starts. |
| Platform secrets | _platform |
Shared namespace. Consumed by Integrations via platformSecret mapping. |
Master Key
Set via the ROOTCX_MASTER_KEY environment variable (hex-encoded 32-byte key), or auto-generated in config/master.key on first boot.
Using Studio
Use the Secret Vault panel to add, view, and delete secrets. Secrets are organized by scope: select an Application to manage app-level secrets, or switch to the Platform tab for shared secrets. Plaintext values are write-only and never displayed after saving.
Using Code
App Secrets
Set a secret
POST /api/v1/apps/{appId}/secrets
{ "key": "STRIPE_KEY", "value": "sk_test_..." }
List keys
GET /api/v1/apps/{appId}/secrets
Returns key names only. Plaintext is never returned.
Delete
DELETE /api/v1/apps/{appId}/secrets/{key}
Platform Secrets
POST /api/v1/platform/secrets
{ "key": "SLACK_TOKEN", "value": "xoxb-..." }
GET /api/v1/platform/secrets
DELETE /api/v1/platform/secrets/{key}
Platform secrets are consumed by Integrations that declare a platformSecret mapping in their configSchema:
"configSchema": {
"properties": {
"botToken": {
"type": "string",
"platformSecret": "SLACK_TOKEN"
}
}
}
The runtime reads the value from the vault and injects it into the Integration backend at runtime.
Backend Injection
App secrets are decrypted and injected as environment variables when the backend process starts:
// Vault key: STRIPE_KEY → process.env.STRIPE_KEY
const stripe = new Stripe(process.env.STRIPE_KEY!);
Secrets added or updated after the backend is running require a restart to take effect.