Skip to content

Secret Manager

The Secret Manager provides secure storage for sensitive data with support for multiple backends and secret scoping (global, organization, project, user).

BackendCLI ValuePersistenceNotes
macOS Data Protection Keychaindata-protection-keychainPersistentHardware-backed (Apple Silicon). Requires Developer ID signing. macOS default — auto-falls back to login keychain if unsigned.
macOS KeychainkeychainPersistentSystem keychain integration
Windows Credential Managercredential-managerPersistentProtected by user account
Linux Secret Servicesecret-servicePersistentGNOME Keyring, KWallet, etc.
Linux keyutilskeyutilsSession-onlyKernel keyring, lost on reboot
FilefilePersistentINSECURE - development only
Environment VariablesenvRead-onlyReads from env vars, cannot write
AWS Secrets ManagerawsPersistentCloud-native, supports rotation
HashiCorp VaultvaultPersistentKV v2 engine

When no backend is specified, the system auto-detects:

  • macOS → Data Protection Keychain (falls back to login Keychain if binary is unsigned)
  • Windows → Credential Manager
  • Linux → Secret Service (falls back to File if D-Bus unavailable)
Terminal window
sideseat --secrets-backend vault
# or
SIDESEAT_SECRETS_BACKEND=env sideseat
{
"secrets": {
"backend": "vault",
"vault": {
"address": "https://vault.internal:8200",
"mount": "secret",
"prefix": "sideseat"
}
}
}

Priority: CLI args > env vars > config file > platform auto-detect.

Reads secrets from environment variables. Read-only — the server cannot create or update secrets.

{
"secrets": {
"backend": "env",
"env": {
"prefix": "SIDESEAT_SECRET_"
}
}
}

Environment variable names are derived from the secret key path:

Secret KeyEnvironment Variable
global/jwt_signing_keySIDESEAT_SECRET_GLOBAL_JWT_SIGNING_KEY
org/acme/api_keySIDESEAT_SECRET_ORG_ACME_API_KEY
project/p1/tokenSIDESEAT_SECRET_PROJECT_P1_TOKEN
user/u1/personal_tokenSIDESEAT_SECRET_USER_U1_PERSONAL_TOKEN

Required secrets must be pre-configured as environment variables before starting the server with the env backend:

Environment VariableSecret Key
SIDESEAT_SECRET_GLOBAL_JWT_SIGNING_KEYglobal/jwt_signing_key
SIDESEAT_SECRET_GLOBAL_API_KEY_SECRETglobal/api_key_secret
Env VarDescription
SIDESEAT_SECRETS_ENV_PREFIXOverride the env var prefix (default: SIDESEAT_SECRET_)

Each secret is stored as an individual AWS Secrets Manager secret.

{
"secrets": {
"backend": "aws",
"aws": {
"region": "us-east-1",
"prefix": "sideseat"
}
}
}

Authentication uses the standard AWS SDK credential chain (env vars, instance profile, SSO).

Env VarDescription
SIDESEAT_SECRETS_AWS_REGIONAWS region
SIDESEAT_SECRETS_AWS_PREFIXPrefix for secret names (default: sideseat)

Uses the KV v2 secrets engine via HTTP API.

{
"secrets": {
"backend": "vault",
"vault": {
"address": "https://vault.internal:8200",
"mount": "secret",
"prefix": "sideseat"
}
}
}

Authentication uses a Vault token. Priority: SIDESEAT_SECRETS_VAULT_TOKEN env var > VAULT_TOKEN env var (standard Vault convention) > secrets.vault.token in config file.

Env VarDescription
SIDESEAT_SECRETS_VAULT_ADDRVault server address (required)
VAULT_TOKEN / SIDESEAT_SECRETS_VAULT_TOKENAuthentication token (required)
SIDESEAT_SECRETS_VAULT_MOUNTKV v2 mount path (default: secret)
SIDESEAT_SECRETS_VAULT_PREFIXPrefix within mount (default: sideseat)

Secrets are organized into four scope levels:

ScopeKey FormatExample
Globalglobal/{name}global/jwt_signing_key
Organizationorg/{org_id}/{name}org/acme/openai_api_key
Projectproject/{project_id}/{name}project/p1/webhook_secret
Useruser/{user_id}/{name}user/u1/personal_token
SecretScopeRationale
jwt_signing_keyGlobalInfrastructure: one signing key for all JWTs
api_key_secretGlobalInfrastructure: HMAC key for API key hashing
Third-party API keysOrganizationOrg isolation: each org has own keys
Webhook secretsProjectPer-project configuration
Personal access tokensUserUser-specific credentials

Secrets can be looked up with a fallback chain across scopes:

// Try org-scoped first, fall back to global
secrets.get_with_fallback("openai_api_key", &[
SecretScope::org("acme"),
SecretScope::global(),
])

Existing local vault files (v1) use flat keys (jwt_signing_key). The new system (v2) uses scoped keys (global/jwt_signing_key). Migration happens automatically on startup:

  1. Files without a version field are treated as v1
  2. All flat keys are prefixed with global/
  3. Version is set to 2 and saved immediately

No manual intervention needed.

Cloud backends (AWS, Vault) run periodic health checks every 60 seconds. Local and env backends use a no-op health check. Failed health checks are logged as warnings but do not stop the server.

  • Secret values are never logged — only key names appear in logs
  • The Secret type redacts values in debug output ([REDACTED])
  • OS-native backends use platform encryption (Keychain, Credential Manager)
  • File backend stores secrets in plain text — use only for development
  • Corrupted vault files are backed up and a fresh vault is created