# Application-level overrides for the standalone template. # # The library ships its declarative defaults in # @o3co/auth-provider-core/reference.conf # (resolved at boot via standalone/src/app.mts withFallback chain). # Values omitted here inherit from that baseline; add overrides only # for keys this deployment intentionally diverges on. http { port = 3000 port = ${?HTTP_PORT} trustProxy = false trustProxy = ${?HTTP_TRUST_PROXY} } oauth { grants { # Template is a typical web-app OP — enable the universal user-auth path. # client_credentials remains off (reference.conf default); deployments that # need M2M flows set OAUTH_GRANTS_CLIENT_CREDENTIALS_ENABLED=true or add # `client_credentials { enabled = true }` in their own application.conf. # # The env-override line (`enabled = ${?OAUTH_GRANTS_*_ENABLED}`) is repeated # at this layer because HOCON precedence: application.conf wins over # reference.conf, so without the env-override line at the template layer, # an operator setting OAUTH_GRANTS_SESSION_ENABLED=false (etc.) cannot # disable the grant — the env var only takes effect at the layer where # the substitution is written. session { enabled = true enabled = ${?OAUTH_GRANTS_SESSION_ENABLED} } authorization_code { enabled = true enabled = ${?OAUTH_GRANTS_AUTHORIZATION_CODE_ENABLED} pkce { requireS256 = false requireS256 = ${?OAUTH_GRANTS_AUTHORIZATION_CODE_PKCE_REQUIRE_S256} } } refresh_token { enabled = true enabled = ${?OAUTH_GRANTS_REFRESH_TOKEN_ENABLED} } # client_credentials: omitted -> inherits reference.conf default (enabled = false). # Operators that need M2M flows set OAUTH_GRANTS_CLIENT_CREDENTIALS_ENABLED=true # or add `client_credentials { enabled = true }` here. } # OR-9: adapter switch for the OAuth authorization-code repository. When # set to "redis", the standalone composition root wires # `redisCodeRepositoryModule` against the shared ioredis socket # (`standaloneRedisClientsModule`). Memory-only deployments lose codes on # restart and across replicas — multi-replica production MUST use "redis". # Supersedes the legacy `repositories.code.type` switch (kept below for # one release cycle for backward compat). code { adapter = "redis" adapter = ${?OAUTH_CODE_ADAPTER} } } session { secret = ${?SESSION_SECRET} # MIN-2: __Host- prefix requires Secure, Path=/, and no Domain attribute. # If SESSION_SECURE=false or SESSION_DOMAIN is set, also override # SESSION_NAME to a non-__Host- value. name = "__Host-auth.session" name = ${?SESSION_NAME} maxAge = 3600000 maxAge = ${?SESSION_MAX_AGE} secure = true secure = ${?SESSION_SECURE} sameSite = "lax" sameSite = ${?SESSION_SAME_SITE} domain = null domain = ${?SESSION_DOMAIN} storage { type = "redis" type = ${?SESSION_STORAGE_TYPE} redis { url = "redis://localhost:6379" url = ${?SESSION_STORAGE_REDIS_URL} password = ${?SESSION_STORAGE_REDIS_PASSWORD} } } } # Rate limiting for SESSION routes (e.g. /session/login bruteforce protection). # Uses windowMs (milliseconds) — consumed by express-rate-limit in Session.mts. # NOTE (IH-18): this section does NOT govern OAuth endpoint rate limiting. # For OAuth rate limiting (/token, /authorize), use the `rateLimiter` # component (memoryRateLimiterModule or redisRateLimiterModule) with # its own `memoryRateLimiter.*` / `redisRateLimiter.*` config section # (uses `windowSeconds` instead of `windowMs`). Switch via # `rateLimiter.adapter = "memory" | "redis"` (see reference.conf). rateLimit { # `login` is per-deployment tuning (bruteforce-window + limit), kept in # this layer so operators can tweak without forking reference.conf. login { windowMs = 900000, limit = 20 } # rateLimit.failMode: inherits reference.conf default ("closed"). # Deployments that prefer fail-open override here: # failMode = "open" # failMode = ${?RATE_LIMIT_FAIL_MODE} } federations { # Template ships a Google federation declaration disabled-by-default. # Operators enable + populate credentials via env vars. google { enabled = false enabled = ${?FEDERATIONS_GOOGLE_ENABLED} clientId = ${?FEDERATIONS_GOOGLE_CLIENT_ID} clientSecret = ${?FEDERATIONS_GOOGLE_CLIENT_SECRET} callbackURL = "http://localhost:3000/session/oauth/federation/google/callback" callbackURL = ${?FEDERATIONS_GOOGLE_CALLBACK_URL} } } repositories { client { type = "yaml" type = ${?CLIENT_TYPE} yaml { path = "./config/clients.yaml" path = ${?CLIENT_PATH} } } user { type = "http" type = ${?CLIENT_USER_TYPE} yaml { path = "./config/users.yaml" } http { authenticateUrl = ${?CLIENT_USER_AUTHENTICATE_URL} authenticateByTokenUrl = ${?CLIENT_USER_AUTHENTICATE_BY_TOKEN_URL} timeout = 5000 timeout = ${?CLIENT_USER_TIMEOUT} } } code { type = "redis" type = ${?CLIENT_CODE_TYPE} memory { defaultExpiresIn = 600 defaultExpiresIn = ${?CLIENT_CODE_DEFAULT_EXPIRES_IN} } redis { defaultExpiresIn = 600 defaultExpiresIn = ${?CLIENT_CODE_DEFAULT_EXPIRES_IN} endpointUri = ${?CLIENT_CODE_ENDPOINT_URI} password = ${?CLIENT_CODE_PASSWORD} } } } endpoints { login { url = "/login" url = ${?ENDPOINTS_LOGIN_URL} } # IH-10: `client { url }` and `authCallback { url }` removed — no # production consumer reads them. } cors { allowedOrigins = [] } # D-2 v2 + Wave 5d: ioredis connection-config consumed by the shared # `standaloneRedisClientsModule` in `templates/standalone/src/modules.mts`. # One ioredis socket per replica backs ALL Redis-typed clients (RT family # + 4 user-session stores + rate limiter). Multi-replica deployments MUST # point this at a shared Redis 7.2+ instance — without it, each replica # stores RT families in its own ioredis connection against a local-only # Redis, defeating the cross-replica persistence purpose. refreshTokenFamilyStore { redis { url = "redis://localhost:6379" url = ${?REFRESH_TOKEN_FAMILY_STORE_REDIS_URL} password = ${?REFRESH_TOKEN_FAMILY_STORE_REDIS_PASSWORD} } }