Configuration reference
The main environment variables of the auth-service, family by family: database, encryption, sessions, email, sign-in policies, storage and observability.
The auth-service follows the 12-factor model: all configuration comes from environment variables, loaded and validated at startup. This page lists the main variables by family, with their exact defaults.
How configuration is loaded
An invalid or missing required value stops the service at boot with an explicit error, never a silent fallback. Durations use the Go syntax (30m, 24h, 720h); booleans accept true and false. Two production guards are enforced: with APP_ENV=production, SESSION_SECURE must be true and MAIL_TRANSPORT=log is refused. SESSION_SECURE=true is also required whenever OIDC_ISSUER uses HTTPS.
Core service
| Variable | Role | Default |
|---|---|---|
APP_ENV | development or production; production enables strict guards | development |
HTTP_ADDR | Listen address of the API | :8080 |
LOG_LEVEL | Level of the JSON structured logs | info |
OIDC_ISSUER | Public URL of the API: the iss claim and the base of discovery URLs | http://localhost:8080 |
LOGIN_UI_URL | Public URL of the sign-in UI (magic links point to it) | http://localhost:3000 |
ALLOWED_DATA_REGIONS | Data-residency regions allowed for tenants (CSV) | eu |
Database and Redis
| Variable | Role | Default |
|---|---|---|
DATABASE_URL | PostgreSQL connection string; holds all durable state | required |
REDIS_URL | Redis connection string; sessions and rate limiting, volatile | required |
On managed services, use sslmode=verify-full for PostgreSQL and rediss:// for Redis: TLS end to end.
Encryption at rest
| Variable | Role | Default |
|---|---|---|
ENCRYPTION_KEY | Primary AES-256-GCM key: encrypts TOTP secrets and the private OIDC signing keys stored in the database (base64, exactly 32 bytes) | required |
ENCRYPTION_KEY_OLD | Previous keys (CSV), kept for decryption only during a key rotation | empty |
Generate a key:
openssl rand -base64 32Store ENCRYPTION_KEY in a secrets vault, separately from database backups. A restored dump is unreadable without the key that encrypted its secrets.
Sessions, cookies and proxies
| Variable | Role | Default |
|---|---|---|
SESSION_TTL | Session lifetime | 24h |
SESSION_SECURE | Marks cookies Secure; mandatory in production | false |
SESSION_COOKIE_NAME | Name of the session cookie | obexal_session |
SESSION_COOKIE_DOMAIN | Cookie domain, if shared across subdomains | empty |
COOKIE_SAMESITE | lax, strict or none | lax |
CSRF_COOKIE_NAME | Name of the CSRF cookie | obexal_csrf |
ALLOWED_ORIGINS | CORS origins allowed to call the API (CSV) | empty |
TRUSTED_PROXIES | CIDR ranges of reverse proxies whose X-Forwarded-For is honored | empty |
Leave TRUSTED_PROXIES empty and the service only trusts the TCP peer address: behind a proxy, all clients collapse onto the proxy IP and per-IP rate limiting stops working.
Token lifetimes
| Variable | Role | Default |
|---|---|---|
OAUTH_ACCESS_TOKEN_TTL | Access token lifetime | 10m |
OAUTH_ID_TOKEN_TTL | ID token lifetime | 10m |
OAUTH_REFRESH_TOKEN_TTL | Refresh token lifetime | 720h |
OAUTH_AUTH_CODE_TTL | Authorization code lifetime | 1m |
These lifetimes also bound the grace period of a signing key rotation.
Email delivery
| Variable | Role | Default |
|---|---|---|
MAIL_TRANSPORT | smtp or log (debug: prints emails to the logs, refused in production) | log |
SMTP_HOST | SMTP relay host (choose an EU relay) | empty |
SMTP_PORT | SMTP port | 587 |
SMTP_USERNAME | SMTP user | empty |
SMTP_PASSWORD | SMTP password | empty |
MAIL_FROM | Sender address | no-reply@obexal.local |
Sign-in and account policies
| Variable | Role | Default |
|---|---|---|
REQUIRE_EMAIL_VERIFICATION | Blocks password sign-in for unverified email addresses | false |
EMAIL_OTP | Requires an email code as second factor on password sign-in when the user has no TOTP | true |
MFA_ENROLLMENT_STRICT | When a tenant requires MFA, rejects authenticated requests (403) until a factor is enrolled | false |
ORG_SIGNUP_ENABLED | Allows self-service organization creation | true |
ACCOUNT_SELF_DELETE_ENABLED | Lets end users delete their own account (consumer tenants only) | false |
ACCOUNT_SELF_EMAIL_CHANGE_ENABLED | Lets end users change their own email address (consumer tenants only) | false |
Rate limiting and lockout
| Variable | Role | Default |
|---|---|---|
RATE_LIMIT_LOGIN_MAX | Login attempts per account per window | 10 |
RATE_LIMIT_LOGIN_WINDOW | Login rate-limit window | 15m |
RATE_LIMIT_LOGIN_IP_MAX | Login attempts per IP per window | 100 |
RATE_LIMIT_SIGNUP_MAX | Sign-ups per identifier per window | 5 |
RATE_LIMIT_SIGNUP_WINDOW | Sign-up rate-limit window | 1h |
RATE_LIMIT_SIGNUP_IP_MAX | Sign-ups per IP per window | 50 |
LOGIN_LOCKOUT_MAX | Failed attempts before locking an account (0 or less disables) | 10 |
LOGIN_LOCKOUT_WINDOW | Window counting the failures | 15m |
LOGIN_LOCKOUT_DURATION | Lock duration | 15m |
Local data files
Two optional features read local files, with no network call and no data leaving your perimeter:
| Variable | Role | Default |
|---|---|---|
GEOIP_DB_PATH | Path to a .mmdb GeoIP database for country rules in conditional access | empty |
BREACHED_PASSWORD_FILE | Path to a breached password corpus, HIBP SHA1:count format or plain text | empty |
Both fail open: if the file is missing or unreadable, the feature stays inert and nothing is blocked. Refresh the GeoIP file periodically (it is loaded at startup).
Object storage (tenant logos)
| Variable | Role | Default |
|---|---|---|
S3_ENDPOINT | S3-compatible endpoint, host:port without scheme | empty |
S3_ACCESS_KEY | Access key | empty |
S3_SECRET_KEY | Secret key | empty |
S3_BUCKET | Bucket for tenant branding assets | obexal-branding |
S3_USE_SSL | TLS towards the endpoint | false |
S3_REGION | Region label of the S3 protocol | us-east-1 |
Logo upload is cleanly disabled unless endpoint, access key and secret key are all set. The default region label is only an S3 protocol convention used by MinIO: no US service is involved.
Webhooks and audit
| Variable | Role | Default |
|---|---|---|
WEBHOOK_WORKERS | Size of the delivery worker pool | 4 |
WEBHOOK_QUEUE_SIZE | Delivery queue capacity | 256 |
WEBHOOK_TIMEOUT | Timeout of each delivery attempt | 10s |
WEBHOOK_ALLOW_PRIVATE_TARGETS | Allows webhook URLs pointing to private or loopback addresses | false |
AUDIT_RETENTION | Retention of the audit log; 0 disables purging | 0 |
WEBHOOK_ALLOW_PRIVATE_TARGETS=true is for development only. In production it opens the door to SSRF: a tenant admin could target your internal network. Keep it false.
AI agents
| Variable | Role | Default |
|---|---|---|
AGENT_AUTO_CONTAINMENT_ENABLED | Automatically contains an AI agent whose activity spikes far beyond its baseline (applies the kill switch) | true |
Observability
| Variable | Role | Default |
|---|---|---|
METRICS_ENABLED | Exposes GET /metrics in Prometheus format | true |
METRICS_TOKEN | If set, requires Authorization: Bearer on /metrics | empty |
HTTP_REQUEST_TIMEOUT | Per-request processing timeout (503 beyond it); 0 disables | 15s |
Variables consumed by other components
These are not read by the auth-service:
OBEXAL_CONNECT_SRC: theconnect-srcCSP directive of the login and admin UIs. Tighten it to the exact API origin in production.NEXT_PUBLIC_OBEXAL_API_URL,NEXT_PUBLIC_LOGIN_UI_URL,NEXT_PUBLIC_ADMIN_URL,NEXT_PUBLIC_ALLOWED_REDIRECTS: build arguments baked into the UI images.OBEXAL_ACME_EMAIL,OBEXAL_API_HOST,OBEXAL_ADMIN_HOST,OBEXAL_LOGIN_HOST: consumed by the Caddy TLS overlay (see Deploy with Docker Compose).