Configuration Reference
OctoFHIR is configured via a TOML file (default: octofhir.toml). All options can be overridden via environment variables using the OCTOFHIR__ prefix.
Configuration File Location
Section titled “Configuration File Location”# Default location./octofhir.toml
# Custom location via environment variableOCTOFHIR_CONFIG=/path/to/config.toml ./octofhir-serverEnvironment Variable Overrides
Section titled “Environment Variable Overrides”Any configuration option can be overridden via environment variables:
# Pattern: OCTOFHIR__SECTION__SUBSECTION__KEYOCTOFHIR__SERVER__PORT=9000OCTOFHIR__STORAGE__POSTGRES__HOST=db.example.comOCTOFHIR__AUTH__OAUTH__ACCESS_TOKEN_LIFETIME=2hServer Configuration
Section titled “Server Configuration”[server]# Network bindinghost = "0.0.0.0" # Listen addressport = 8888 # Listen port
# Request handlingread_timeout_ms = 15000 # Read timeout (15s)write_timeout_ms = 15000 # Write timeout (15s)body_limit_bytes = 1048576 # Max request body (1 MiB)Storage Configuration
Section titled “Storage Configuration”PostgreSQL
Section titled “PostgreSQL”[storage.postgres]# Option 1: Connection URL (takes precedence)url = "postgres://user:pass@localhost:5432/octofhir"
# Option 2: Individual settingshost = "localhost"port = 5450user = "postgres"password = "postgres"database = "octofhir"
# Connection poolpool_size = 20 # Max connectionsconnect_timeout_ms = 10000 # Connection timeout (10s)idle_timeout_ms = 60000 # Idle connection timeout (60s)FHIR Configuration
Section titled “FHIR Configuration”[fhir]# Supported versions: R4, R4B, R5, R6version = "R4"
[validation]# Allow clients to skip validation via X-Skip-Validation headerallow_skip_validation = true
[search]default_count = 10 # Default page sizemax_count = 100 # Maximum page sizeFHIR Packages
Section titled “FHIR Packages”[packages]# Base directory for package storagepath = ".fhir"
# Packages to load on startupload = [ "hl7.fhir.r4.core#4.0.1", "hl7.fhir.us.core#6.1.0"]Authentication & Authorization
Section titled “Authentication & Authorization”OAuth 2.0 Settings
Section titled “OAuth 2.0 Settings”[auth]# Issuer URL (should match your public URL)issuer = "http://localhost:8888"
[auth.oauth]# Token lifetimesauthorization_code_lifetime = "10m"access_token_lifetime = "1h"refresh_token_lifetime = "90d"
# Security settingsrefresh_token_rotation = true
# Allowed grant typesgrant_types = ["authorization_code", "client_credentials", "refresh_token"]SMART on FHIR
Section titled “SMART on FHIR”[auth.smart]# Launch modeslaunch_ehr_enabled = truelaunch_standalone_enabled = true
# Client typespublic_clients_allowed = trueconfidential_symmetric_allowed = trueconfidential_asymmetric_allowed = true
# Featuresrefresh_tokens_enabled = trueopenid_enabled = truedynamic_registration_enabled = false
# Supported scopessupported_scopes = [ "openid", "fhirUser", "launch", "launch/patient", "offline_access", "patient/*.cruds", "user/*.cruds", "system/*.cruds"]JWT Signing
Section titled “JWT Signing”[auth.signing]# Algorithm: RS256, RS384, or ES384algorithm = "RS384"
# Key rotationkey_rotation_days = 90keys_to_keep = 3
# Optional: Fixed keys for token persistence across restarts# kid = "my-key-id"# private_key_pem = """-----BEGIN PRIVATE KEY-----..."""# public_key_pem = """-----BEGIN PUBLIC KEY-----..."""Access Policies
Section titled “Access Policies”[auth.policy]default_deny = true # Deny when no policy matchesquickjs_enabled = true # Enable JavaScript policy engine
[auth.policy.quickjs]memory_limit_mb = 16max_stack_size_kb = 256timeout_ms = 100Rate Limiting
Section titled “Rate Limiting”[auth.rate_limiting]token_requests_per_minute = 60token_requests_per_hour = 1000auth_requests_per_minute = 30max_failed_attempts = 5lockout_duration = "5m"Sessions & Cookies
Section titled “Sessions & Cookies”[auth.cookie]enabled = truename = "octofhir_token"secure = false # Set true in production (HTTPS)http_only = truesame_site = "lax"path = "/"
[auth.session]idle_timeout = "30m"absolute_timeout = "8h"max_concurrent_sessions = 10cookie_name = "octofhir_sso"cookie_secure = false # Set true in productionIdentity Federation
Section titled “Identity Federation”[auth.federation]allow_external_idp = trueauto_provision_users = falsejwks_cache_ttl = "1h"jwks_refresh_on_failure = trueCaching
Section titled “Caching”Redis (for horizontal scaling)
Section titled “Redis (for horizontal scaling)”[redis]enabled = false # Enable for multi-instanceurl = "redis://localhost:6380"pool_size = 10timeout_ms = 5000
[cache]terminology_ttl_secs = 3600local_cache_max_entries = 10000Features
Section titled “Features”GraphQL
Section titled “GraphQL”[graphql]enabled = trueintrospection = true # Disable in production for securitymax_depth = 15max_complexity = 500DB Console
Section titled “DB Console”[db_console]enabled = truesql_mode = "admin" # readonly | readwrite | adminlsp_enabled = trueSQL on FHIR
Section titled “SQL on FHIR”[sql_on_fhir]enabled = trueTerminology
Section titled “Terminology”[terminology]server_url = "https://tx.fhir.org/r4"cache_ttl_secs = 3600Audit Trail
Section titled “Audit Trail”[audit]enabled = falselog_fhir_operations = truelog_auth_events = truelog_read_operations = truelog_search_operations = trueexclude_resource_types = ["AuditEvent"]Observability
Section titled “Observability”Logging
Section titled “Logging”[logging]# trace | debug | info | warn | error | offlevel = "info"OpenTelemetry
Section titled “OpenTelemetry”[otel]enabled = falseendpoint = "http://localhost:4318"sample_ratio = 0.1 # 10% samplingBootstrap
Section titled “Bootstrap”Initial setup on first run:
[bootstrap.admin_user]username = "admin"password = "admin123" # Change in production!email = "admin@example.com"
[bootstrap.backend_client]client_id = "backend"client_secret = "dev-secret-2024"scopes = ["system/*.cruds"]name = "Backend Service"Production Example
Section titled “Production Example”[server]host = "0.0.0.0"port = 8888
[storage.postgres]url = "postgres://user:pass@prod-db.example.com:5432/octofhir?sslmode=require"pool_size = 50
[fhir]version = "R4"
[validation]allow_skip_validation = false
[auth]issuer = "https://fhir.example.com"
[auth.cookie]secure = truesame_site = "strict"
[auth.session]cookie_secure = true
[redis]enabled = trueurl = "redis://prod-redis.example.com:6379"
[graphql]introspection = false
[logging]level = "warn"
[otel]enabled = trueendpoint = "https://otel.example.com:4318"sample_ratio = 0.01