Configuration

Runtime configuration, secrets, and provider-specific SMTP settings.

Use this page to decide which files belong to local development, which values must come from secrets, and what must change when moving the service to production.

Configuration Model

The service has three configuration layers: static userver component configuration, startup/runtime variables, and userver dynamic config. Static configuration defines which components, task processors, listeners, handlers, and config-service clients exist. Runtime variables provide environment-specific values such as ports, database URLs, JWT keys, SMTP credentials, and config-service endpoints. Dynamic config controls runtime policy such as auth limits and outbox retry behavior.

File Use Production rule
configs/static_config.yaml Local development and testsuite-enabled workflows. Do not use for internet-facing production if it enables test handlers.
configs/static_config.prod.yaml Production component graph and HTTP handlers. Use this file for production containers.
configs/config_vars.yaml Runtime values loaded by the static config. Ignored locally; generate or mount it from a secret store in production.
configs/config_vars.docker.example.yaml Tracked example that documents the runtime config shape. Keep demo-safe; copy it as a starting point, never as a production secret source.
configs/config_vars.docker.yaml Ignored local Docker/devcontainer runtime values. Create it from the tracked example; local real credentials may live here because it is not committed.
.env Docker Compose variables for local Postgres and migration jobs. Keep it untracked and environment-specific.

Secret Delivery Model

Production should treat the Docker image as immutable and secret-free. The compose defaults point at ignored local prod-style paths for manual smoke runs, while the deploy layer reads a secret source such as a platform secret store, Vault, Yandex Lockbox, Kubernetes Secret, or Docker secret, renders config_vars.yaml, and mounts it read-only into the container. JWT key files are mounted through a separate secrets directory referenced by AUTH_JWT_PRIVATE_KEY_PATH and AUTH_JWT_PUBLIC_KEY_PATH.

SMIRKLY_CONFIG_VARS_PATH=/etc/smirkly-auth/config_vars.yaml \
SMIRKLY_SECRETS_PATH=/run/secrets/smirkly-auth \
docker compose --profile prod up --build -d smirkly-auth

SMTP passwords, database passwords, migration database URLs, refresh token pepper, and JWT private keys must not be committed, baked into the image, or stored in tracked demo configs. Changing these values requires regenerating the mounted config or secret and restarting the service instances.

Dynamic Config

Runtime policy is stored in typed userver dynamic configs so the code reads snapshots instead of scattered hard-coded values. Local development and Docker run from the C++ defaults defined in dynamic_config::Key. Production connects dynamic-config-client and dynamic-config-client-updater to config-service and keeps a filesystem cache for restart fallback.

Key Controls Change model
SMIRKLY_AUTH_RUNTIME_CONFIG Sign-up and sign-in rate limits, verified-email sign-in requirement, session activity write threshold, verification code TTL, and verification attempt limits. Safe runtime policy; validate values before rollout.
SMIRKLY_EMAIL_OUTBOX_RUNTIME_CONFIG Outbox processing kill switch, batch size, max attempts, stuck timeout, and retry backoff. Safe for incidents, for example disabling delivery or lowering batch size.

Do not put secrets, DSNs, JWT private keys, SMTP credentials, listener ports, config-service endpoints, or task processor thread counts into the auth/outbox dynamic config keys. Those values shape the process or contain secret material and require deploy-time configuration plus rolling restart. In production, dynamic-config-updates-enabled should be true, dynamic-config-cache-path should be writable and persistent, and config updates should be monitored through userver metrics.

The repository contains tracked examples for the production dynamic config handoff. Use configs/dynamic_config/values.example.json as a seed for config-service storage. A userver-compatible config-service returns the same object wrapped under configs, with updated_at metadata, as shown in configs/dynamic_config/config_service_response.example.json. The auth process reads neither file directly in production; it receives the HTTP response through dynamic-config-client-updater. Local development can stay on C++ defaults by keeping dynamic-config-updates-enabled: false.

Runtime Variables

Setting Required Notes
event-threads Yes Userver event loop threads. Startup config; change with a rolling restart.
worker-threads Yes Main userver task processor size for request handling.
worker-fs-threads Yes Filesystem/blocking utility processor size.
worker-monitor-threads Yes Dedicated processor for monitor/admin handlers.
worker-email-outbox-threads Yes Dedicated SMTP delivery processor. Keep email delivery off the main request path.
logger-level Yes Use info in production unless debugging a controlled incident.
is-testing Yes Must be false outside testsuite or local test runs.
server-port Yes HTTP listen port inside the container.
monitor-server-port Yes Private monitor listener port for /health/live, /health/ready, and /service/*. Restrict at network level.
postgres-dbconnection Yes Postgres DSN used by the service. Keep aligned with migration DSN for the same environment.
AUTH_JWT_AUDIENCE Yes Audience claim expected by downstream services.
AUTH_JWT_KEY_ID Yes Stable key id exposed as token kid and in JWKS.
AUTH_JWT_PRIVATE_KEY_PATH Yes Path to the RSA private key mounted inside the runtime container.
AUTH_JWT_PUBLIC_KEY_PATH Yes Path to the RSA public key served through JWKS.
AUTH_REFRESH_TOKEN_PEPPER Yes Secret pepper for HMAC-SHA256 refresh token hashes. Rotate only through a planned session invalidation or migration.

SMTP Variables

Email verification depends on the outbox worker and the SMTP variables below. Values are provider-specific, so production should use the provider documentation and a secret store, not copied local credentials.

Setting Example Production guidance
AUTH_SMTP_HOST smtp.gmail.com Use a controlled relay or transactional provider for production.
AUTH_SMTP_PORT 465 Use 465 for implicit TLS or 587 for STARTTLS.
AUTH_SMTP_TLS_MODE tls Use tls with port 465, starttls with port 587, and none only for fake local SMTP.
AUTH_SMTP_USERNAME your-account@gmail.com Use provider-issued credentials with the narrowest available scope.
AUTH_SMTP_APP_PASSWORD <secret> Never commit it. Rotate immediately after exposure in chat, logs, screenshots, or git.
AUTH_SMTP_FROM_EMAIL no-reply@example.com Must be authorized by provider policy and aligned with SPF, DKIM, and DMARC.
AUTH_SMTP_FROM_NAME Smirkly Human sender name displayed by email clients.
AUTH_SMTP_HOST: smtp.gmail.com
AUTH_SMTP_PORT: 465
AUTH_SMTP_TLS_MODE: tls
AUTH_SMTP_USERNAME: your-account@gmail.com
AUTH_SMTP_APP_PASSWORD: "<gmail-app-password>"
AUTH_SMTP_FROM_EMAIL: your-account@gmail.com
AUTH_SMTP_FROM_NAME: "Smirkly"

Client IP and Proxy Headers

The service can use forwarded client IP headers only when the immediate peer is a trusted proxy. Configure trusted proxy CIDRs to match the ingress or load balancer ranges exactly. Do not trust arbitrary X-Forwarded-For or X-Real-IP values from the public internet.

Change Rules

  • Changing source code requires a rebuild and service restart.
  • Changing config_vars.yaml requires a service restart, not a rebuild.
  • Changing migrations requires running the migration job before the new service version starts.
  • Changing JWT keys requires a planned rotation window and downstream JWKS cache awareness.