Skip to content

Settings reference

Every settings key Vaultbase reads from the vaultbase_settings table.

Runtime configuration lives in the vaultbase_settings table — keyed by string, valued by string. Edited from the admin Settings page; values are cache-invalidated on save.

Secret-valued keys — names ending in .password, .pass, .secret, .client_secret, .api_key, .private_key, .access_key, .token, .service_account and similar — read back as ******** from GET /api/v1/admin/settings and the MCP settings tools. Sending ******** back in a PATCH keeps the stored value; any other value (including "") replaces it.

KeyTypeDefaultNotes
rate_limit.enabled"1"/"0""1"Master switch. When unset, the VAULTBASE_RATE_ENABLED env var (0 = off) sets the default.
rate_limit.rulesJSON array(defaults below)See shape below
rate_limit.max / rate_limit.window_msint—Legacy single rule (*), used only when rate_limit.rules is empty and both are set.

rate_limit.rules shape:

[
{ "label": "*:auth", "max": 10, "windowMs": 3000, "audience": "all" },
{ "label": "*:create", "max": 60, "windowMs": 5000, "audience": "all" },
{ "label": "/api/*", "max": 300, "windowMs": 10000, "audience": "all" }
]

label syntax: <path>[:<action>]

  • path — exact (/api/v1/posts), prefix (/api/*), or wildcard (*). /api/v1/... and /api/... are equivalent.
  • action — auth, create, list, view, update, delete
  • audience — all, guest (no token), auth (any user/admin token)
KeyTypeDefault
smtp.enabled"1"/"0""0"
smtp.hoststring—
smtp.portstring (int)"587"
smtp.secure"1"/"0""0"
smtp.userstring—
smtp.passstring—
smtp.fromstring— — e.g. "Acme" <noreply@acme.com>; must be an address or Name <address>

Test via Settings → SMTP → Send test. The cache TTL is 30 seconds.

KeyTypeDefaultNotes
email.transportstring"smtp"Name of a registered email transport; an unknown name is rejected with 422.
KeyTypeDefault
app.urlstring— — base URL of your frontend; used in {{link}}
email.verify.subjectstring"Verify your email"
email.verify.bodystring(multi-line default)
email.reset.subjectstring"Reset your password"
email.reset.bodystring(multi-line default)
email.otp.subjectstring"Your sign-in code"
email.otp.bodystring(multi-line default)
email.email_change.subjectstring"Confirm your new email address"
email.email_change.bodystring(multi-line default)
email.invite.subjectstring"You're invited"
email.invite.bodystring(multi-line default)

Variables in templates: {{email}}, {{token}}, {{code}} (otp only), {{link}}, {{appUrl}}, {{collection}}. In email_change, {{email}} is the new address; in invite, the invited address. Empty values fall back to the defaults. All five are edited at Settings → Email templates.

KeyDefaultNotes
auth.otp.enabled"0" (off)Magic link / OTP flow. Requires SMTP.
auth.mfa.enabled"1" (on)TOTP enrollment. Disabling blocks new enrollment only — existing users keep working.
auth.anonymous.enabled"0" (off)POST .../anonymous
auth.impersonation.enabled"1" (on)Admin can impersonate users

Disabled features return 422 with a clear message.

KeyDefaultNotes
auth.admin.window_seconds604800 (7 d)Admin JWT lifetime.
auth.user.window_seconds604800 (7 d)User JWT lifetime.
auth.anonymous.window_seconds2592000 (30 d)Anonymous user JWT lifetime.
auth.impersonate.window_seconds3600 (1 h)Impersonation token lifetime.
auth.refresh.window_seconds604800 (7 d)Refresh window.
auth.file.window_seconds3600 (1 h)File download token lifetime.
auth.session.max_seconds2592000 (30 d)How long a sign-in can be kept alive through refresh, from the original sign-in. 0 = no cap.

Window keys accept 60–31536000 seconds (1 minute to 365 days); auth.session.max_seconds accepts 0 or at least 3600. Other values are rejected with 422.

HTTP API cross-origin allow-list. Edited from Settings → CORS. Empty origin list blocks all cross-origin requests (defensive default).

KeyTypeDefaultNotes
cors.originscomma-separated""* permits any origin (incompatible with credentials → silently downgraded to echoing matched origin).
cors.methodscomma-separatedGET,POST,PUT,PATCH,DELETE,OPTIONS
cors.headerscomma-separatedAuthorization,Content-Type,If-Match,X-VB-Idempotency-Key
cors.credentials"1"/"0""0"Sends Access-Control-Allow-Credentials: true.
cors.max_ageseconds"600"Preflight cache lifetime. A negative value is refused.

Cache TTL 5s; preflight is short-circuited at onRequest.

Applies whenever a password is set — admin creation and password changes, auth-collection sign-ups, resets and changes — not at login. Defaults are off — only length is enforced (12 characters minimum, floor 8).

KeyTypeDefaultNotes
password.min_lengthint"12"Floor 8 (NIST 800-63B).
password.require_upper"1"/"0""0"Reject if no uppercase letter.
password.require_lower"1"/"0""0"Reject if no lowercase letter.
password.require_digit"1"/"0""0"Reject if no digit.
password.require_symbol"1"/"0""0"Reject if no non-alphanumeric character.
password.hibp_check"1"/"0""0"k-anonymity check against api.pwnedpasswords.com. Fails open on network error.

Per-account + per-IP failed-login throttle. On by default. The IP limit is 5 × max_attempts. Behind a reverse proxy, set security.trusted_proxies (or the env var) so the IP is the real client’s, not the proxy’s.

KeyTypeDefaultNotes
auth.lockout.max_attemptsint"10""0" = off. Lockout fires when failures within window reach this.
auth.lockout.duration_secondsint"900"Window seconds. Min 60 (15 min default); a smaller value is refused.

Setting overrides VAULTBASE_TRUSTED_PROXIES env. Without either, vaultbase ignores X-Forwarded-For entirely (defensive default — prevents spoofing on direct-exposed deployments).

KeyTypeDefaultNotes
security.trusted_proxiescomma-separated IPs / CIDRs""Affects ratelimit + audit log + brute-force IP keying. An entry that isn’t an IP or CIDR is refused.
security.allowed_originscomma-separated origins""Origins allowed to open realtime (WebSocket / SSE) connections. Empty = same-origin only; * allows any. Requests without an Origin header (non-browser clients) are allowed.

Prometheus exposition at /api/v1/metrics. Off by default. Optional bearer auth via metrics.token.

KeyTypeDefaultNotes
metrics.enabled"1"/"0""0"Master switch. 404 when off.
metrics.tokenstring""Required as Authorization: Bearer <token>. Empty = only an admin token is accepted.

Always available to admins as JSON at /api/v1/_/metrics.

Edited at Settings → File storage.

KeyTypeDefaultNotes
files.max_upload_sizeint (bytes)"52428800" (50 MB)Per upload request; 413 above it. Range 1024–134217728 (128 MB, the server’s request body limit); other values are rejected with 422.
files.orphan_cleanup"1"/"0""1"Periodic sweep that deletes stored files no record references any more (after a grace period; collections with record history are skipped). "0" turns it off.
storage.driverstring"local"Storage driver name (local, s3, or one an extension registers). An unknown name is rejected with 422.
s3.endpointstring""S3-compatible endpoint URL.
s3.bucketstring""
s3.regionstring"auto"
s3.access_key_idstring""
s3.secret_access_keystring""Encrypted at rest; reads back masked.
s3.public_urlstring""Optional public base URL for objects.

Scheduled database backups. Edited at Settings → Backups.

KeyTypeDefaultNotes
backups.enabled"1"/"0""0"Turns scheduled backups on.
backups.croncron (UTC)"0 3 * * *"Schedule. An invalid expression is rejected with 422.
backups.keepint"7"Backups to keep per location. Range 1–1000 (422 otherwise).
backups.s3.enabled"1"/"0""0"Also upload each backup to S3.
backups.s3.endpointstring""
backups.s3.bucketstring""
backups.s3.regionstring"auto"
backups.s3.prefixstring"vaultbase-backups/"Key prefix for uploaded backups.
backups.s3.access_key_idstring""
backups.s3.secret_access_keystring""Encrypted at rest; reads back masked.

backups.last_run_at, backups.last_error and backups.next_run are written by the scheduler (status, not configuration).

KeyTypeDefaultNotes
api.openapi_public"1"/"0""0"Serve GET /api/v1/openapi.json to non-admins. They don’t see collections whose list, view and create rules are all admin-only. Admins can always read it.
flags.public_evaluate"1"/"0""1"Allow POST /api/v1/flags/evaluate without a session. "0" returns 401 to anonymous callers.

Edited at Settings → Data retention. A cleanup runs once a day.

KeyTypeDefaultNotes
maintenance.retention_daysint (days)"30"Finished queue jobs, finished webhook deliveries and daily request-log files older than this are deleted. 0 keeps them forever. Range 0–3650 (422 otherwise). Expired token revocations and one-time auth tokens are always cleaned up.
audit.retention_daysint (days)"0"Admin audit-log entries older than this are deleted daily. 0 keeps them forever. Range 0–3650.

Admin UI accent + surface colors. Edited at Settings → Theme. Empty value falls back to the built-in default. Hex format only (#RGB, #RRGGBB, #RRGGBBAA). The login page picks up the operator’s overrides too.

KeyCSS variableDefault
theme.accent--accent#e85a4f
theme.accent_hover--accent-hover#f06f64
theme.accent_light--accent-light#f5807a
theme.bg_app--bg-app#0e0f12
theme.bg_sidebar--bg-sidebar#131418
theme.bg_panel--bg-panel#181a1f
theme.text_primary--text-primary#e6e8ed
theme.text_secondary--text-secondary#9aa0ac
theme.success--success#22c55e
theme.warning--warning#f59e0b
theme.danger--danger#ef4444

Public read endpoint: GET /api/v1/admin/theme — admin SPA fetches it before mounting React.

Polls GitHub for the latest release tag. Boot delay 30 s, then every 6 h. Vaultbase never auto-updates — this is purely a notification.

KeyTypeDefaultNotes
update_check.enabled"1"/"0""1"Master switch.
update_check.latest_versionstring(cached)Last tag fetched from GitHub.
update_check.checked_atunix-seconds(cached)Last successful check.
update_check.errorstring(cached)Last fetch error, cleared on success.

Outbound helpers.http.* calls from hooks/routes/cron pass through a CIDR filter. See Hooks → Egress filter for the default deny list and DNS-rebind caveat.

KeyTypeDefaultNotes
hooks.http.denycomma-separated CIDRs(default-deny RFC1918 + link-local + loopback)Replaces defaults. off disables filtering. An entry that isn’t a CIDR is refused.
hooks.http.allowcomma-separated CIDRs""Allow exceptions evaluated after deny. An entry that isn’t a CIDR is refused.

Cache TTL 5s; PATCH /api/v1/admin/settings invalidates immediately.

For each of google, github, gitlab, facebook, microsoft, discord, twitch, spotify, linkedin, slack, bitbucket, notion, patreon, twitter, oidc:

KeyType
oauth2.<name>.enabled"1"/"0"
oauth2.<name>.client_idstring
oauth2.<name>.client_secretstring

A provider counts as “enabled” only when all three are set + enabled is "1".

Provider-specific keys:

KeyNotes
oauth2.apple.client_id, oauth2.apple.team_id, oauth2.apple.key_id, oauth2.apple.private_keyApple signs its client secret with this key instead of using client_secret. private_key is encrypted at rest.
oauth2.oidc.authorization_url, oauth2.oidc.token_url, oauth2.oidc.userinfo_urlEndpoints of your OIDC provider.
oauth2.oidc.scopesScopes to request.
oauth2.oidc.display_nameButton label. Default OIDC.

Redirect allow-list:

KeyDefaultNotes
oauth2.allowed_redirect_uris""Comma-separated redirect URIs a sign-in may return to. A trailing * extends the path; * alone allows any. Empty = only the origin of app.url.
oauth2.<name>.allowed_redirect_uris—Per-provider override of the list above.

See Push notifications for end-to-end setup.

KeyType
notifications.providers.onesignal.enabled"1"/"0"
notifications.providers.onesignal.app_idstring (UUID)
notifications.providers.onesignal.api_keystring (REST API key — encrypted at rest)
notifications.providers.fcm.enabled"1"/"0"
notifications.providers.fcm.project_idstring (optional — defaults to project_id from the service account JSON)
notifications.providers.fcm.service_accountstring (full service-account.json contents — encrypted at rest)

Settings whose key matches a secret-shaped suffix are AES-GCM-encrypted before being written to vaultbase_settings and decrypted on read. The wrapper is the same vbenc:1:<iv>:<ciphertext> envelope used by encrypted record fields (core/encryption.ts), so backups + snapshots stay symmetric.

Suffixes that trigger encryption (case-insensitive): .password, .pass, .api_key, .apikey, .secret, .client_secret, .private_key, .privatekey, .access_key, .accesskey, .service_account, .token.

The key is VAULTBASE_ENCRYPTION_KEY, or, when that is unset, a key generated on first start into <dataDir>/.encryption-key. Secret settings stored in plaintext before a key existed are encrypted at startup. If the key changes so that it no longer decrypts the stored secrets, Vaultbase refuses to start and says how to restore the right key (see Encrypted fields → Key rotation).

GET /api/v1/admin/settings ← admin auth
PATCH /api/v1/admin/settings { "<key>": "<value>", ... }

PATCH is partial — keys not in the body are left untouched. The whole PATCH is rejected with 422 if any value fails validation. Settings caches (rate-limit, SMTP, storage, CORS, hook egress) are invalidated on save. The MCP vaultbase.update_setting tool applies the same validation and cache refreshes.

Settings are not exposed to hooks or routes through ctx.helpers. For automation, use PATCH /api/v1/admin/settings from an admin session, or the MCP settings tools (vaultbase.list_settings, get_setting, update_setting, scope mcp:admin) with an API token.