# Configuration keys

This page lists every configuration key of an instance, with its environment variable, its type, its default and what it accepts; it is generated from the key table of the repository's configuration handbook, which a test holds to the gateway's own loader.

A key is set in the YAML file named by `VAUBAAN_CONFIG_FILE` or by its environment variable; when both set a key, the file wins, silently. Secrets may also be given as `${NAME}` or `${file:/path}` references in the file, or through the `*_FILE` variables. Anything required and missing stops the instance at start with exit code 78 and a message naming every key. How the sources combine: [configuration](/docs/configuration).

| Key | Environment variable | Type | Default | Accepted values |
| --- | --- | --- | --- | --- |
| `public_url` | `VAUBAAN_PUBLIC_URL` | URL | required | https; no query or fragment; a trailing `/` is stripped, a sub-path is kept |
| `instance_name` | `VAUBAAN_INSTANCE_NAME` | string | — | 1 to 64 characters; trimmed; no control character, line or paragraph separator, nor bidirectional override or isolate (`checkInstanceName`, `config/instance-name.ts`); blank is not set |
| `trusted_proxies` | `VAUBAAN_TRUSTED_PROXIES` | list | — | —; each entry an IP address or a CIDR block (prefix 0–32 for IPv4, 0–128 for IPv6) |
| `self_resources` | `VAUBAAN_SELF_RESOURCES` | list | — | —; each entry `<provider>:<ref>` (a plugin id, then the resource ref as discovery stores it); `railway:$RAILWAY_PROJECT_ID` is always added when Railway sets that variable, `fly:$FLY_APP_NAME` when Fly sets that one |
| `client_ip_header` | `VAUBAAN_CLIENT_IP_HEADER` | enum | — | `x-real-ip`, `cf-connecting-ip`, `true-client-ip`, `fly-client-ip`; not together with `trusted_proxies`; off by default |
| `store.path` | `VAUBAAN_STORE_PATH` | string | required | —; not empty |
| `restore.from` | `VAUBAAN_RESTORE_FROM`, `VAUBAAN_RESTORE_FROM_FILE` | secret | — | —; an https URL (a redirect only to https, five at most) or an absolute file path; http refused; never echoed nor logged |
| `restore.sha256` | `VAUBAAN_RESTORE_SHA256` | string | — | —; 64 hexadecimal characters; required with `restore.from` |
| `restore.max_mb` | `VAUBAAN_RESTORE_MAX_MB` | integer | `1024` | 1 to 65536; in mebibytes |
| `encryption.master_key` | `VAUBAAN_MASTER_KEY`, `VAUBAAN_MASTER_KEY_FILE` | secret | required | —; exactly 32 bytes, in base64 or base64url |
| `encryption.key_version` | `VAUBAAN_MASTER_KEY_VERSION` | integer | `1` | >= 1 |
| `encryption.previous_keys` | `VAUBAAN_MASTER_KEY_PREVIOUS`, `VAUBAAN_MASTER_KEY_PREVIOUS_FILE` | secret map | — | —; `{version: key}` (`1=<b64>,2=<b64>` in the variable); a version is an integer >= 1 other than `key_version`; each key 32 bytes, base64 |
| `idp.issuer` | `VAUBAAN_IDP_ISSUER` | URL | required once `idp` is set | https |
| `idp.client_id` | `VAUBAAN_IDP_CLIENT_ID` | string | required once `idp` is set | — |
| `idp.client_secret` | `VAUBAAN_IDP_CLIENT_SECRET`, `VAUBAAN_IDP_CLIENT_SECRET_FILE` | secret | required once `idp` is set | — |
| `idp.claims.sub` | `VAUBAAN_IDP_CLAIM_SUB` | string | `sub` | — |
| `idp.claims.email` | `VAUBAAN_IDP_CLAIM_EMAIL` | string | `email` | — |
| `idp.claims.groups` | `VAUBAAN_IDP_CLAIM_GROUPS` | string | `groups` | — |
| `idp.allowed_email_domains` | `VAUBAAN_IDP_ALLOWED_EMAIL_DOMAINS` | list | — | —; lower-cased; empty: everyone the directory signs in — refused for an open issuer (personal Google or Microsoft) without `idp.invitation_only` |
| `idp.invitation_only` | `VAUBAAN_IDP_INVITATION_ONLY` | boolean | `false` | —; not together with `idp.allowed_email_domains` |
| `sign_in.<id>.<field>` | `VAUBAAN_SIGN_IN_<ID>_<FIELD>` (`KIND`, `NAME`, `ISSUER`, `CLIENT_ID`, `CLIENT_SECRET` and its `_FILE`, `CLAIM_SUB`, `CLAIM_EMAIL`, `CLAIM_GROUPS`, `CLAIM_EMAIL_VERIFIED`, `ALLOWED_EMAIL_DOMAINS`, `INVITATION_ONLY`, `REQUIRE_VERIFIED_EMAIL`; `-` in the id ↔ `_` in the variable) | string | — | `kind`, `name`, `issuer`, `client_id`, `client_secret`, `claims.sub`, `claims.email`, `claims.groups`, `claims.email_verified`, `allowed_email_domains`, `invitation_only`, `require_verified_email`; the id is a lower-case letter then letters, digits or hyphens (32 at most), not `idp` when the `idp` block is set; `kind` is `oidc` or `github`; `issuer` https, required for `oidc`, default `https://github.com` for `github`; no `claims` and no `require_verified_email` for `github`; `claims.email_verified` defaults to `email_verified` (Entra ID: `xms_edov`), `require_verified_email` to false (true: an unverified email is refused, as on an open provider); one issuer per provider; an open provider needs domains or `invitation_only` |
| `admin.group` | `VAUBAAN_ADMIN_GROUP` | string | — | —; **admin rule**: at least one of `admin.group` and `admin.emails`; `<provider>:<group>` (a GitHub group is `org/team`); a bare name only while one sign-in provider is configured |
| `admin.emails` | `VAUBAAN_ADMIN_EMAILS` | list | — | —; lower-cased; each entry contains `@` |
| `providers.<id>.<field>` | `VAUBAAN_PROVIDER_<ID>_<FIELD>` (`_FILE` for `client_secret` and `private_key`; `-` in the id ↔ `_` in the variable) | string | — | `client_id`, `client_secret`, `app_id`, `app_slug`, `private_key`; the field is one of these and its value is not empty; the id is a registered plugin (checked by the root) |
| `bootstrap_token` | `VAUBAAN_BOOTSTRAP_TOKEN`, `VAUBAAN_BOOTSTRAP_TOKEN_FILE` | secret | required while no sign-in provider is set | at least 32 characters; refused once `bootstrap.revoked_at` is set in the store |
| `telemetry.enabled` | `VAUBAAN_TELEMETRY_ENABLED` | boolean | `false` | — |
| `telemetry.level` | `VAUBAAN_TELEMETRY_LEVEL` | enum | `usage-stats` | `plugin-health`, `usage-stats` |
| `telemetry.collector_url` | `VAUBAAN_TELEMETRY_COLLECTOR_URL` | URL | `https://telemetry.vaubaan.com/v1/reports` | https; a query is allowed (the collector's public key as `?apikey=`) |
| `retention_days` | `VAUBAAN_RETENTION_DAYS` | integer | `90` | >= 1 |
| `requests.expiry` | `VAUBAAN_REQUEST_EXPIRY` | duration | `24h` | — |
| `approvals.expiry` | `VAUBAAN_APPROVAL_EXPIRY` | duration | `10m` | — |
| `mcp.rate_limit_per_minute` | `VAUBAAN_MCP_RATE_LIMIT_PER_MINUTE` | integer | `600` | >= 1 |
| `git.max_pack_mb` | `VAUBAAN_GIT_MAX_PACK_MB` | integer | `200` | 1 to 4096; in mebibytes |
| `git.request_timeout` | `VAUBAAN_GIT_REQUEST_TIMEOUT` | duration | `10m` | at most 3600 s |
| `oauth.access_token_ttl` | `VAUBAAN_OAUTH_ACCESS_TOKEN_TTL` | duration | `15m` | at most 3600 s; that is `1h` |
| `oauth.refresh_token_ttl` | `VAUBAAN_OAUTH_REFRESH_TOKEN_TTL` | duration | `30d` | —; longer than `oauth.access_token_ttl` |
| `oauth.delegation_max_lifetime` | `VAUBAAN_OAUTH_DELEGATION_MAX_LIFETIME` | duration | `90d` | —; longer than `oauth.access_token_ttl` |
| `oauth.refresh_reuse_window_seconds` | `VAUBAAN_OAUTH_REFRESH_REUSE_WINDOW_SECONDS` | integer | `30` | 0 to 60; `0` disables the window |
| `oauth.client_registration.policy` | `VAUBAAN_OAUTH_CLIENT_REGISTRATION_POLICY` | enum | `operator-approved` | `open`, `operator-approved`, `closed` |
| `oauth.client_registration.auto_approve_loopback` | `VAUBAAN_OAUTH_CLIENT_REGISTRATION_AUTO_APPROVE_LOOPBACK` | boolean | `true` | — |
| `oauth.client_registration.metadata_documents` | `VAUBAAN_OAUTH_CLIENT_REGISTRATION_METADATA_DOCUMENTS` | boolean | `false` | — |
| `log.level` | `VAUBAAN_LOG_LEVEL` | enum | `info` | `debug`, `info`, `warn`, `error` |

Source: the "Configuration keys" table of [docs/handbook/configuration.md](https://github.com/vaubaan/gateway/blob/main/docs/handbook/configuration.md#configuration-keys), which also says which part of the code reads each key.
