Skip to content

Configuration

authserver serve resolves configuration in three layers, highest priority last:

  1. Built-in defaults — sensible for localhost development.
  2. YAML file — passed via --config /etc/authserver/config.yaml.
  3. Environment variables — every YAML key has an AUTHPLANE_* equivalent, evaluated after the YAML file and overriding matching keys.

Ship one YAML file per environment and inject secrets via env (docker -e, Kubernetes env:, systemd Environment=). Boot validation fails fast: any “required-when” slot left empty (e.g. a non-localhost issuer without a session secret) stops the server with an error naming the missing field.

Exact names, YAML keys, and defaults from the generated reference. The full table — every variable with types and required-when rules — lives at docs/reference/env-vars.md.

Env varYAML keyDefaultPurpose / example
AUTHPLANE_SERVER_ISSUERserver.issuerhttp://localhost:9000Public issuer URL — https://auth.example.com (HTTPS, no trailing slash)
AUTHPLANE_SERVER_ADDRESSserver.address:9000Public OAuth listener
AUTHPLANE_ADMIN_ADDRESSadmin.address:9001Admin API + UI + /metrics listener — keep internal
AUTHPLANE_ADMIN_API_KEYadmin.api_keyRequired when admin is enabled and issuer isn’t localhost. openssl rand -hex 32; min 16 chars, obvious values (changeme, dev-admin-key, …) rejected at boot
AUTHPLANE_SESSION_SECRETsession.secretRequired when issuer isn’t localhost. openssl rand -hex 32 (≥ 32 bytes)
AUTHPLANE_SESSION_SECUREsession.securefalseSet true once TLS is live
AUTHPLANE_SERVER_ALLOWED_ORIGINSserver.allowed_originsCORS origins for browser-based MCP clients — empty disables CORS (startup WARN)
AUTHPLANE_STORAGE_DRIVERstorage.driversqlitesqlite (single instance) or postgres (HA)
AUTHPLANE_STORAGE_POSTGRES_DSNstorage.postgres.dsnRequired when driver is postgrespostgres://authserver@db/authserver?sslmode=require
AUTHPLANE_STORAGE_POSTGRES_MAX_CONNSstorage.postgres.max_conns25Tune against replica count × pool size
AUTHPLANE_SIGNING_KEY_STOREsigning.key_storekeyfilekeyfile, postgres_key (multi-replica), or vault_transit
AUTHPLANE_SIGNING_KEY_PATHsigning.key_pathdata/keysKey directory when store is keyfile — back it up
AUTHPLANE_SIGNING_ALGORITHMsigning.algorithmES256JWT signing algorithm
AUTHPLANE_VAULT_ADDRsigning.vault_transit.addressRequired when key store is vault_transithttps://vault.vault.svc:8200
AUTHPLANE_DATA_ENCRYPTION_DRIVERdata_encryption.driveraes_master or vault_transit_encrypt — encrypts refresh tokens, Token Vault broker grants, and postgres_key blobs at rest
AUTHPLANE_DATA_ENCRYPTION_KEY_ENVdata_encryption.aes_master.key_envName of the env var holding the 64-hex AES master key
AUTHPLANE_CLIENT_CREDENTIALS_ENABLEDclient_credentials.enabledfalseMachine-to-machine / agent identity (RFC 6749 §4.4)
AUTHPLANE_DPOP_ENABLEDdpop.enabledfalseSender-constrained tokens (RFC 9449)
AUTHPLANE_TOKEN_EXCHANGE_ENABLEDtoken_exchange.enabledfalseDelegation + Token Vault upstream vends (RFC 8693)
AUTHPLANE_OIDC_ENABLEDoidc.enabledFederate login to an upstream OIDC IdP (Google, Okta, Dex)
AUTHPLANE_LOG_LEVELobservability.logging.levelinfodebug for dev stacks
AUTHPLANE_LOG_FORMATobservability.logging.formatjsonStructured logs to stdout
AUTHPLANE_TRACING_ENABLEDobservability.tracing.enabledfalseOTLP trace export; endpoint via AUTHPLANE_TRACING_ENDPOINT
AUTHPLANE_METRICS_PROVIDERobservability.metrics.providerprometheusprometheus, otel, or both
AUTHPLANE_RATE_LIMIT_ENABLEDrate_limit.enabledtrueToken-bucket limiting — 100 rps (AUTHPLANE_RATE_LIMIT_RPS), burst 200 (AUTHPLANE_RATE_LIMIT_BURST)

Optional grants ship off to keep a fresh install minimal — with a flag off, POST /oauth/token returns unsupported_grant_type even if the client lists the grant. Every machine-to-machine MCP integration needs at least client_credentials:

FlagEnvTurn it on for
client_credentials.enabledAUTHPLANE_CLIENT_CREDENTIALS_ENABLEDService-account / agent identity flows
dpop.enabledAUTHPLANE_DPOP_ENABLEDSender-constrained tokens, once clients support it
token_exchange.enabledAUTHPLANE_TOKEN_EXCHANGE_ENABLEDDelegation, scope narrowing, Token Vault
oidc.enabledAUTHPLANE_OIDC_ENABLEDUpstream IdP login (requires oidc.issuer, oidc.client_id, oidc.client_secret, oidc.redirect_uri)
xaa.enabledYAML onlyCross-App Access — enterprise IdP-managed auth via ID-JAG assertions
SecretRequired whenHow
session.secret (AUTHPLANE_SESSION_SECRET)issuer is not localhostopenssl rand -hex 32
admin.api_key (AUTHPLANE_ADMIN_API_KEY)admin enabled, issuer not localhostopenssl rand -hex 32
connect.state_secretbroker providers / Token Vault Connect flowopenssl rand -hex 32 (min 32 chars)
AES master key (env named by data_encryption.aes_master.key_env)data_encryption.driver: aes_masteropenssl rand -hex 32 (exactly 64 hex chars = 256-bit)
server:
issuer: https://auth.example.com # Must be HTTPS, no trailing slash
shutdown_wait: 20s
allowed_origins: ["https://app.example.com"] # Or browser MCP clients fail CORS
storage:
driver: postgres # AUTHPLANE_STORAGE_DRIVER
postgres:
dsn: "" # Inject via AUTHPLANE_STORAGE_POSTGRES_DSN
max_conns: 25 # Tune against replica count × pool size
signing:
algorithm: ES256
key_store: postgres_key # Multi-replica safe; requires data_encryption
postgres_key:
encryption_key_env: AUTHPLANE_SIGNING_KEY_ENC
data_encryption:
driver: aes_master
aes_master:
key_env: AUTHPLANE_DATA_ENC_KEY # Hex 64-char; mint with: openssl rand -hex 32
session:
secure: true # Required for HTTPS issuer
same_site: lax
secret: "" # Inject via AUTHPLANE_SESSION_SECRET
admin:
enabled: true
address: "127.0.0.1:9001" # Loopback or internal-only
api_key: "" # Inject via AUTHPLANE_ADMIN_API_KEY
client_credentials:
enabled: true # Flip on for machine-to-machine
observability:
logging: { level: info, format: json }
metrics: { provider: prometheus, path: /metrics }

Then run with secrets injected via env:

Terminal window
export AUTHPLANE_STORAGE_POSTGRES_DSN="postgres://authserver@db/authserver?sslmode=require"
export AUTHPLANE_SESSION_SECRET=$(openssl rand -hex 32)
export AUTHPLANE_ADMIN_API_KEY=$(openssl rand -hex 32)
export AUTHPLANE_SIGNING_KEY_ENC=$(openssl rand -hex 32)
export AUTHPLANE_DATA_ENC_KEY=$(openssl rand -hex 32)
authserver serve --config /etc/authserver/config.yaml

Verify the listeners and admin auth:

Terminal window
curl -fsS http://localhost:9000/health | jq .
curl -fsS http://localhost:9000/.well-known/oauth-authorization-server | jq -r .issuer
curl -fsS -H "Authorization: Bearer $AUTHPLANE_ADMIN_API_KEY" \
http://localhost:9001/admin/stats | jq .

Next: Docker · Kubernetes · Observability