Skip to content

Server Configuration

Use this page when you run SigID yourself or operate a SigID deployment. It is for platform engineers, SREs, and security owners who need to configure the runtime, database, networking, secrets, production guards, and observability.

For workspace launch decisions, use Launch Your Workspace. For application integration, use Add SigID Login.

Configuration Sources

SigID loads configuration in this order:

  1. built-in defaults
  2. sigid.toml in the working directory, or the file pointed to by SIGID_CONFIG_FILE
  3. environment variable overrides

The repository root includes these starting points:

File Use
sigid.example.toml Complete commented server configuration
.env.example Local environment variable examples
docker/sigid.org.toml Docker development configuration

Environment variables use SIGID_ with __ between nested keys. For example:

SIGID_SERVER__PORT=3000
SIGID_SECURITY__PRODUCTION=true
SIGID_OPENAPI__ENABLED=false

DATABASE_URL is also accepted as a direct override for [database].url.

For single-tenant local development, [tenant].default_tenant_slug = "dev" skips subdomain-based tenant resolution and routes requests to that tenant slug.

Choose a Deployment Topology

SigID can run as one process or as separate runtime planes.

Topology Use when Configuration
All-in-one Local development, small deployments, first production rollout Keep deployment.allow_all_in_one_runtime_plane = true
Split plane You want separate scaling or isolation for auth, control, and async workloads Set deployment.allow_all_in_one_runtime_plane = false and run one process per SIGID_RUNTIME_PLANE

The [deployment] section controls runtime shape:

Setting Purpose
allow_all_in_one_runtime_plane Allows one process to serve every plane
background_tasks_enabled Lets this process run background workers; disable for canary request-serving slots
embedded_chain_monitor Runs chain monitoring in the server process when chain monitoring is configured
coordination_backend Shared state backend: postgres, redis, or memcached
database_topology Database routing mode: shared or split_by_plane

Coordination backends use these companion sections:

Backend Required config Other settings
postgres No extra section; uses the configured database Default backend
redis [redis].url [redis].pool_size
memcached [memcached].address pool_size, max_idle, connect_timeout_secs, command_timeout_secs

Redis is active when deployment.coordination_backend = "redis" and redis.url is set. Memcached is active when deployment.coordination_backend = "memcached" and memcached.address is set.

Runtime Planes

Set SIGID_RUNTIME_PLANE when you run split-plane deployments.

Value Purpose
all Serve all runtime planes in one process; only valid when all-in-one mode is allowed
auth Authentication, OAuth, sessions, hosted login, user-facing identity routes
control Management APIs, admin routes, OpenAPI docs when enabled
async Background workers, event processing, async maintenance work

When deployment.allow_all_in_one_runtime_plane = false, startup requires SIGID_RUNTIME_PLANE=auth, SIGID_RUNTIME_PLANE=control, or SIGID_RUNTIME_PLANE=async.

Server And Networking

The [server] section controls the HTTP listener, first-party origins, CORS, proxy trust, host validation, metrics authentication, throttling, and shutdown behavior.

Setting Purpose
host, port Listen address and port
transport plain_http for local/non-production, tls_h2_only for production
base_domain Primary domain for cookie scoping and tenant routing
identity_app_origin First-party identity app origin
dashboard_app_origin First-party dashboard app origin
allowed_hosts Host-header allowlist; required in production
trusted_proxies Proxy IPs/CIDRs allowed to supply X-Forwarded-For
direct_client_exposure Explicit acknowledgement that the process is directly exposed without a trusted proxy
metrics_bearer_token Optional static bearer token for Prometheus scrapes
endpoint_throttle Per-endpoint throttling rules
request_timeout_secs Per-request deadline; production rejects 0
shutdown_deadline_secs Graceful shutdown deadline; production rejects 0

server.transport = "tls_h2_only" terminates TLS in-process and requires HTTP/2 ALPN. Configure [server.tls] with cert_pem_path and key_pem_path. Set ca_pem_path when local clients, such as container health checks, need an explicit trust bundle for the direct listener.

Production mode rejects server.transport = "plain_http". Local development can still use plain HTTP.

Database

The [database] section configures PostgreSQL URLs, pool sizing, timeouts, and SSL requirements.

Setting Purpose
url Shared runtime database URL
identity_url Required identity/session database URL
auth_url Optional auth-plane database URL
control_url Optional control-plane database URL
async_url Optional async-plane database URL
migration_url Optional migrator database URL
maintenance_url Optional maintenance database URL
max_connections, min_connections Default pool sizing
connect_timeout_secs Database connection timeout
idle_timeout_secs, max_lifetime_secs Connection recycling controls
statement_cache_capacity Prepared statement cache size per connection
test_before_acquire Validate pooled connections before use
statement_timeout_secs Request-serving SQL statement timeout
idle_in_transaction_timeout_secs Timeout for sessions idle inside transactions
maintenance_statement_timeout_secs Longer timeout for maintenance operations
require_ssl Require TLS for database connections

For shared topology, set [database].url or DATABASE_URL. For split-plane topology, set deployment.database_topology = "split_by_plane" and provide plane URLs as needed. Missing plane URLs fall back to [database].url.

Plane-specific pool sections override pool sizing when the matching runtime plane is active:

[database.auth_pool]
max_connections = 64
min_connections = 8

[database.control_pool]
max_connections = 24
min_connections = 4

[database.async_pool]
max_connections = 16
min_connections = 2

Production mode requires database.require_ssl = true unless the database URL explicitly includes an sslmode= parameter.

KMS And Production Secrets

Production deployments require sigid-kms. Without [kms], non-production starts with ephemeral in-memory keys, which are not suitable for production.

Setting Purpose
socket_path Unix socket path for the local sigid-kms service
server_public_key_path Pinned Noise public key published by sigid-kms
client_private_key_path This runtime's persistent Noise client private key

Several historical secret environment variables are intentionally rejected at startup because those secrets have moved into KMS. If startup reports that a SIGID_* secret has moved to sigid-kms, rotate or provision it through the KMS path instead of adding it back to the process environment.

Auth, Email, Phone, Captcha, And HIBP

The [auth] section controls password hashing, brute-force protection, and registration limits.

Setting Purpose
argon2_memory_kib Password hashing memory cost
argon2_iterations, argon2_parallelism Password hashing time and parallelism
argon2_max_concurrent Concurrent Argon2 verification limit
brute_force_max_attempts, brute_force_lockout_secs Account lockout rules
password_verify_ip_* IP-weighted budget for expensive password verification
registration_rate_limit_* Registration rate limiting

In production on the auth plane, startup enforces the production Argon2 throughput profile, including 64 MiB memory, one parallel lane, bounded iterations, and bounded concurrency.

Production auth-plane deployments also require:

  • email.provider is not log
  • SMTP uses email.smtp.starttls = true when email.provider = "smtp"
  • phone.provider is not log
  • captcha.enabled = true
  • captcha.secret_key is set
  • captcha.fail_mode is not fail-open
  • hibp.enabled = true
  • hibp.fail_mode is not fail-open

For local development, phone.provider = "log" writes only redacted structured logs unless [phone.log].sink is set. Supported sink values are stdout, stderr, and file:/path/to/mailbox.ndjson; the file sink appends JSON Lines with full SMS bodies for browserless simulations. Do not use this provider in production.

JWT

The [jwt] section controls token signing defaults and token lifetimes.

Setting Default Validation
default_algorithm ES256 Must be ES256 or EdDSA
access_token_lifetime_human_secs 900 60..=86400
access_token_lifetime_agent_secs 300 60..=86400
refresh_token_lifetime_human_secs 604800 3600..=7776000
refresh_token_lifetime_agent_secs 86400 3600..=7776000
id_token_lifetime_secs 300 60..=3600
key_rotation_days 30 1..=365

Refresh-token lifetimes must be greater than or equal to the matching access token lifetime. JWT signing-key encryption is handled by sigid-kms in production.

OIDC, First-Party Origins, And Passkeys

The [oidc] section defines the issuer URL and authorization code lifetime. Production mode requires oidc.issuer_url to use HTTPS.

The [passkey] section configures WebAuthn relying-party settings. Keep the passkey origin aligned with the browser origin that users actually visit.

The first-party origins in [server] should match the deployed identity and dashboard frontends:

[server]
identity_app_origin = "https://identity.example.com"
dashboard_app_origin = "https://dashboard.example.com"

Feature Sections

Most feature modules have their own configuration section. Keep this page as the server-level map, then use feature guides for behavior and API details.

Section Purpose
[social] Global social OAuth settings
[enterprise_sso] Enterprise OIDC SSO state secret and callback settings
[generic_oauth] Database-backed arbitrary OAuth/OIDC providers
[phone], [sms] Phone/SMS OTP delivery
[email_otp] Email OTP settings
[magic_link] Magic link passwordless authentication
[anonymous] Anonymous/guest authentication
[two_factor] TOTP, backup codes, trusted devices
[adaptive_mfa] Risk-based step-up authentication
[challenge] Challenge nonce TTL, agent PoW difficulty, agent limits
[device_authorization] RFC 8628 device flow
[session_cookie] Session limits, cache cookies, binding
[admin] Admin panel roles and bootstrap admin user credentials
[access_control] RBAC/ABAC role, policy, and scope limits
[proxy] Outbound proxy mTLS
[oauth_proxy] Development-only OAuth proxy for redirect callbacks
[wallet] Managed wallet signing
[[chains]] Blockchain RPC configuration
[siwe] Sign-In with Ethereum enablement, domain pin, and accepted EIP-155 chain IDs
[api_keys] API key authentication
[i18n] Localization and message catalogs
[billing], [commerce] Billing, plans, checkout, and payment-of-record
[dpop] DPoP sender-constrained token validation
[organizations], [invitations], [verified_domains] B2B organization and domain settings
[vault] Credential storage limits
[webhooks] Webhook subscription limits
[scim] SCIM 2.0 provisioning
[telemetry] Metrics, tracing, audit batching, client telemetry
[refresh_family_cache] Refresh-token family revocation cache
[user_self_service] Account deletion and password-change behavior

Observability: Health And Metrics

Health probes are available under /health:

Route Use What it checks
GET /health/live Liveness probe Process is running
GET /health/startup Startup probe Migrations have run and signing keys are loaded
GET /health/ready Readiness probe Database, signing keys, configured chains, and critical background tasks

The health response only exposes status. Detailed failing checks are written to logs.

Metrics are served from GET /metrics in Prometheus format. Authentication depends on configuration:

Configuration Metrics auth behavior
server.metrics_bearer_token is set Accepts Authorization: Bearer <token>
server.metrics_bearer_token is not set Requires a SigID token with metrics:read

OpenAPI Documentation Endpoints

When [openapi].enabled = true, the OpenAPI router serves:

Route Purpose
GET /openapi.json Raw OpenAPI JSON
router root Scalar interactive API UI

Scalar is the browser UI used to explore the generated OpenAPI specification interactively.

Treat OpenAPI as a development and internal review surface. Production mode rejects openapi.enabled = true because it exposes the full API surface.

Environment Variable Overrides

Environment variables take precedence over TOML. Use generic SIGID_ overrides for ordinary config fields:

SIGID_SERVER__ALLOWED_HOSTS='["identity.example.com","dashboard.example.com"]'
SIGID_SERVER__DIRECT_CLIENT_EXPOSURE=false
SIGID_DEPLOYMENT__DATABASE_TOPOLOGY=split_by_plane

Database URL shortcuts are also supported:

Variable TOML equivalent
SIGID_CONFIG_FILE Config file path
SIGID_RUNTIME_PLANE Runtime plane selection
DATABASE_URL [database].url
SIGID_DATABASE__URL [database].url
DATABASE_IDENTITY_URL [database].identity_url
DATABASE_AUTH_URL [database].auth_url
DATABASE_CONTROL_URL [database].control_url
DATABASE_ASYNC_URL [database].async_url
MIGRATION_DATABASE_URL [database].migration_url
MAINTENANCE_DATABASE_URL [database].maintenance_url
SIGID_SECURITY__PRODUCTION [security].production
SIGID_SERVER__PORT [server].port
SIGID_OPENAPI__ENABLED [openapi].enabled

Use SIGID_CONFIG_FILE=/path/to/sigid.toml when the config file is not in the working directory.

Database Migrations

Run migrations as a separate initialization step:

sigid-runtime --migrate-only

Use MIGRATION_DATABASE_URL when the migrator should connect with a separate database principal. MAINTENANCE_DATABASE_URL is optional; when it is not set, maintenance operations fall back to the migration URL and then the runtime URL.

Production Mode

Set security.production = true for non-local deployments. Startup refuses to continue when non-local indicators, such as public issuer or app origins, are present without production mode.

Production mode enforces these server-level requirements:

Area Startup requirement
KMS [kms] is configured
Transport server.transport is not plain_http
Host validation server.allowed_hosts is populated
Proxy trust server.trusted_proxies is populated, or server.direct_client_exposure = true
Timeouts server.request_timeout_secs and server.shutdown_deadline_secs are greater than 0
Database database.require_ssl = true unless the URL sets sslmode=
OIDC oidc.issuer_url uses HTTPS
OpenAPI openapi.enabled = false
OAuth proxy oauth_proxy.enabled = false
Webhooks security.webhook_allow_non_standard_ports = false
Auth abuse controls CAPTCHA and HIBP are enabled and do not fail open
Email/phone Providers are not log; SMTP uses STARTTLS

Production Hardening Checklist

Before exposing SigID to production traffic, confirm:

  • security.production = true
  • sigid-kms is running and [kms] points to the correct socket and keys
  • server.transport = "tls_h2_only" is configured with the certificate and key paths required by the direct SigID listener
  • server.allowed_hosts contains only expected hostnames
  • server.trusted_proxies contains only your ingress or load balancer ranges, unless direct_client_exposure = true is intentional
  • oidc.issuer_url, identity origin, dashboard origin, and passkey origin use HTTPS
  • database connections require TLS through database.require_ssl or URL sslmode=
  • OpenAPI and OAuth proxy are disabled
  • email, phone, CAPTCHA, and HIBP providers are production providers
  • webhook delivery is restricted to HTTPS default ports
  • /health/startup, /health/ready, and /metrics are wired into your monitoring system
  • migrations run before traffic reaches the new version

Common Startup Errors

Error includes Meaning Fix
security.production must be true Public/non-local deployment indicators were detected without production mode Set security.production = true and complete the production checklist
server.transport = "plain_http" Production mode rejects plain HTTP direct listener Use tls_h2_only or adjust the deployment boundary before enabling production
server.allowed_hosts Host-header validation is not configured Add expected identity, dashboard, and tenant hostnames
trusted_proxies Proxy headers would be ignored or unsafe Add trusted proxy CIDRs, or explicitly set direct_client_exposure = true
database URL is required No runtime database URL was configured Set DATABASE_URL, SIGID_DATABASE__URL, or plane-specific database URLs
database.require_ssl Production database traffic is not marked TLS-protected Set database.require_ssl = true or include sslmode= in the URL
kms must be configured Production key management is missing Configure [kms] and start sigid-kms
openapi.enabled must be false OpenAPI docs are enabled in production Disable [openapi] for production
captcha.enabled or hibp.enabled Auth-plane abuse controls are missing Configure CAPTCHA and HIBP with fail-closed behavior
moved to sigid-kms A removed secret env var is still set Provision that secret through KMS and remove the env var

Next Steps