Settings reference
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.
Rate limiting
Section titled “Rate limiting”| Key | Type | Default | Notes |
|---|---|---|---|
rate_limit.enabled | "1"/"0" | "1" | Master switch |
rate_limit.rules | JSON array | (defaults below) | See shape below |
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 (*)action—auth,create,list,view,update,deleteaudience—all,guest(no token),auth(any user/admin token)
| Key | Type | Default |
|---|---|---|
smtp.enabled | "1"/"0" | "0" |
smtp.host | string | — |
smtp.port | string (int) | "587" |
smtp.secure | "1"/"0" | "0" |
smtp.user | string | — |
smtp.pass | string | — |
smtp.from | string | — — e.g. "Acme" <noreply@acme.com> |
Test via Settings → SMTP → Send test. The cache TTL is 30 seconds.
Email templates
Section titled “Email templates”| Key | Type | Default |
|---|---|---|
app.url | string | — — base URL of your frontend; used in {{link}} |
email.verify.subject | string | "Verify your email" |
email.verify.body | string | (multi-line default) |
email.reset.subject | string | "Reset your password" |
email.reset.body | string | (multi-line default) |
email.otp.subject | string | "Your sign-in code" |
email.otp.body | string | (multi-line default) |
Variables in templates: {{email}}, {{token}}, {{code}} (otp only),
{{link}}, {{appUrl}}, {{collection}}. Empty values fall back to the
defaults.
Auth features
Section titled “Auth features”| Key | Default | Notes |
|---|---|---|
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.
HTTP API cross-origin allow-list. Edited from Settings → CORS. Empty origin list blocks all cross-origin requests (defensive default).
| Key | Type | Default | Notes |
|---|---|---|---|
cors.origins | comma-separated | "" | * permits any origin (incompatible with credentials → silently downgraded to echoing matched origin). |
cors.methods | comma-separated | GET,POST,PUT,PATCH,DELETE,OPTIONS | |
cors.headers | comma-separated | Authorization,Content-Type,If-Match,X-VB-Idempotency-Key | |
cors.credentials | "1"/"0" | "0" | Sends Access-Control-Allow-Credentials: true. |
cors.max_age | seconds | "600" | Preflight cache lifetime. |
Cache TTL 5s; preflight is short-circuited at onRequest.
Password policy
Section titled “Password policy”Applies to admin login + auth-collection registers. Defaults are off — only length is enforced (12 characters minimum, floor 8).
| Key | Type | Default | Notes |
|---|---|---|---|
password.min_length | int | "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. |
Brute-force lockout
Section titled “Brute-force lockout”Per-email + per-IP failed-login throttle. Off by default. Per-IP keying
requires security.trusted_proxies (or env) for accurate client IPs.
| Key | Type | Default | Notes |
|---|---|---|---|
auth.lockout.max_attempts | int | "0" | "0" = off. Lockout fires when failures within window reach this. |
auth.lockout.duration_seconds | int | "900" | Window seconds. Min 60 (15 min default). |
Trusted proxies
Section titled “Trusted proxies”Setting overrides VAULTBASE_TRUSTED_PROXIES env. Without either, vaultbase
ignores X-Forwarded-For entirely (defensive default — prevents spoofing on
direct-exposed deployments).
| Key | Type | Default | Notes |
|---|---|---|---|
security.trusted_proxies | comma-separated CIDRs | "" | Affects ratelimit + audit log + brute-force IP keying. |
Metrics
Section titled “Metrics”Prometheus exposition at /api/v1/metrics. Off by default. Optional bearer
auth via metrics.token.
| Key | Type | Default | Notes |
|---|---|---|---|
metrics.enabled | "1"/"0" | "0" | Master switch. 404 when off. |
metrics.token | string | "" | Required as Authorization: Bearer <token>. Empty = public. |
Always available to admins as JSON at /_/metrics.
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.
| Key | CSS variable | Default |
|---|---|---|
theme.accent | --accent | #3b82f6 |
theme.accent_hover | --accent-hover | #4a8ef7 |
theme.accent_light | --accent-light | #60a5fa |
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.
Update checker
Section titled “Update checker”Polls GitHub for the latest release tag. Boot delay 30 s, then every 6 h. Vaultbase never auto-updates — this is purely a notification.
| Key | Type | Default | Notes |
|---|---|---|---|
update_check.enabled | "1"/"0" | "1" | Master switch. |
update_check.latest_version | string | (cached) | Last tag fetched from GitHub. |
update_check.checked_at | unix-seconds | (cached) | Last successful check. |
update_check.error | string | (cached) | Last fetch error, cleared on success. |
Hook egress (SSRF guard)
Section titled “Hook egress (SSRF guard)”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.
| Key | Type | Default | Notes |
|---|---|---|---|
hooks.http.deny | comma-separated CIDRs | (default-deny RFC1918 + link-local + loopback) | Replaces defaults. off disables filtering. |
hooks.http.allow | comma-separated CIDRs | "" | Allow exceptions evaluated after deny. |
Cache TTL 5s; PATCH /api/v1/admin/settings invalidates immediately.
OAuth2 providers
Section titled “OAuth2 providers”For each of google, github, gitlab, facebook, microsoft, discord,
twitch, spotify, linkedin, slack, bitbucket, notion, patreon:
| Key | Type |
|---|---|
oauth2.<name>.enabled | "1"/"0" |
oauth2.<name>.client_id | string |
oauth2.<name>.client_secret | string |
A provider counts as “enabled” only when all three are set + enabled is "1".
Push notifications
Section titled “Push notifications”See Push notifications for end-to-end setup.
| Key | Type |
|---|---|
notifications.providers.onesignal.enabled | "1"/"0" |
notifications.providers.onesignal.app_id | string (UUID) |
notifications.providers.onesignal.api_key | string (REST API key — encrypted at rest) |
notifications.providers.fcm.enabled | "1"/"0" |
notifications.providers.fcm.project_id | string (optional — defaults to project_id from the service account JSON) |
notifications.providers.fcm.service_account | string (full service-account.json contents — encrypted at rest) |
At-rest encryption of secrets
Section titled “At-rest encryption of secrets”When VAULTBASE_ENCRYPTION_KEY is set, 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.
Without VAULTBASE_ENCRYPTION_KEY set, secret-shaped settings are
stored plaintext (back-compat) and a one-time stderr warning is emitted
per key. If the env var is later removed or rotated to a wrong value,
reads return "" and a warning is logged.
Reading & writing
Section titled “Reading & writing”GET /api/v1/admin/settings ← admin authPATCH /api/v1/admin/settings { "<key>": "<value>", ... }PATCH is partial — keys not in the body are left untouched. Settings caches (rate-limit, SMTP) are invalidated on save.
Programmatic access (server-side)
Section titled “Programmatic access (server-side)”import { getAllSettings, getSetting, setSetting } from "vaultbase/api/v1/settings";
const all = getAllSettings();const port = parseInt(getSetting("smtp.port", "587"));setSetting("auth.otp.enabled", "1");Useful inside hooks/routes via ctx.helpers (which proxies a subset).