Skip to content

Authentication

Set server.ui_enabled: false or CERTVAULT_UI_ENABLED=false to run CertVault without the web console. Headless mode does not initialize bootstrap or OIDC authentication, accept browser session cookies, or register frontend assets and /auth/* routes. Health, readiness, and API-key-authenticated endpoints remain available. Provision API keys with the certvault api-key CLI before disabling the UI.

The bootstrap token is optional. When configured, it provides local or break-glass administrator access. Supply it using one of:

  • CERTVAULT_BOOTSTRAP_ADMIN_TOKEN
  • CERTVAULT_BOOTSTRAP_ADMIN_TOKEN_FILE

The file form is recommended for container deployments.

To disable bootstrap login, omit both environment variables and auth.bootstrap_token_file from YAML. When OIDC is enabled, bootstrap remains available only as a secondary break-glass method. At least one authentication method must be configured to sign in to the web console.

Browser sessions last 8 hours by default. Configure auth.session_duration in YAML or set CERTVAULT_SESSION_DURATION to a duration such as 12h or 1d to override it. This lifetime applies to both bootstrap and OIDC sessions.

auth:
oidc:
issuer_url: https://auth.example.com/realms/homelab
client_id: certvault
client_secret_file: /run/secrets/oidc_client_secret
scopes: [openid, profile, email, groups]
allowed_groups: [cert-admins]

The client secret can be supplied in three ways:

  • Set its value with CERTVAULT_OIDC_CLIENT_SECRET.
  • Set CERTVAULT_OIDC_CLIENT_SECRET_FILE to the path of a mounted secret file.
  • Set auth.oidc.client_secret_file to that file path in YAML, as shown above.

The raw secret value cannot be placed directly in YAML. Use only one secret source.

Register this redirect URI with the OIDC provider:

{server.public_url}/auth/callback

OIDC uses Authorization Code flow with PKCE. Scopes default to openid, profile, email, and groups; configure them with auth.oidc.scopes or the comma-separated CERTVAULT_OIDC_SCOPES override. The openid scope is required. If allowed_groups is empty, every successfully authenticated identity becomes an administrator; configuring an allowlist is strongly recommended.

Each OIDC flow is bound to the initiating browser using an independent random secret in a short-lived, HttpOnly, host-only cookie. The cookie uses SameSite=Lax so the provider’s top-level GET callback can include it. HTTPS deployments use a Secure cookie with the __Host- prefix and Path=/, preventing subdomains from planting the binding. Parallel login tabs use separate flow cookies. Callbacks with missing or mismatched cookies are rejected before state consumption or token exchange; consumed flow cookies are deleted, including when token verification fails. PKCE, nonce, and group checks remain required.

OIDC login flows expire after ten minutes. One shared timer removes abandoned flows and idle rate-limit entries every minute, and stops when the store is idle. The store admits at most 1,024 flows globally and 16 outstanding flows per client IP. Login admission uses token buckets: eight attempts per minute per IP with a burst of eight, and eight attempts per second globally with a burst of 32. Its per-IP rate-limit map is also capped at 1,024 entries.

Rejected /auth/login requests return 429 with Retry-After: 60 before OIDC discovery. Client addresses follow server.trusted_proxies; users behind a shared proxy or NAT share an IP budget unless trusted forwarding is configured correctly. Flow consumption remains single-use, expiry is checked at callback time, and a failed discovery releases the reserved flow immediately.

Web sessions are administrators. API keys are client identities constrained by scopes and certificate allowlists. API keys cannot access audit logs, ACME-account management, API-key management, or the administrator job-history endpoint.