Product documentation
Identity service configuration
Generated reference for the oauthy.* configuration bound by Identity service.
Identity service configuration
Thoryn's own OIDC federation member: login, registration, password reset, magic link, WebAuthn, lockout, sessions, and user import.
oauthy.identity
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/config/IdentityServiceProperties.kt
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.clients[].client-id | String | "hub-client" | |
oauthy.identity.clients[].client-secret | String | "hub-secret" | |
oauthy.identity.clients[].redirect-uri | String | "http://localhost:8080/login/oauth2/code/identity-service" | |
oauthy.identity.clients[].redirect-uri-patterns | List<String> | (empty) | SSO-1166: optional wildcard-pattern allowlist of redirect URIs accepted in addition to redirectUri. |
oauthy.identity.clients[].post-logout-redirect-uris | List<String> | (empty) | SSO-2307: exact-match allow-list of OIDC RP-initiated-logout post_logout_redirect_uri values accepted for this client. |
oauthy.identity.webauthn.rp-id | String | "localhost" | |
oauthy.identity.webauthn.rp-name | String | "Thoryn Identity Service" | |
oauthy.identity.public-base-url | String | "" | SSO-1134: public origin (scheme://host[:port]) of this identity-service instance. |
oauthy.identity.account-unlock
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/unlock/AccountUnlockProperties.kt
SSO-1905: configuration for the self-service account-unlock endpoints (POST /account/unlock/{request,confirm}).
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.account-unlock.token-ttl | Duration | Duration.ofMinutes(15) | How long a freshly-minted unlock token is valid. |
oauthy.identity.account-unlock.from-address | String | "no-reply@thoryn.io" | From address for outbound unlock mail. |
oauthy.identity.anonymizer
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/risk/AnonymizerProperties.kt
SSO-2043: configuration for the anonymizer / VPN / Tor / proxy login detector.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.anonymizer.enabled | Boolean | true | Master enable flag for the anonymizer detector. |
oauthy.identity.attribute-schema.validation
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/attributeschema/AttributeSchemaValidationProperties.kt
SSO-2541 — configuration for ProductApiAttributeSchemaValidationClient, the identity→product-api seam that validates a user-metadata write against the tenant's attribute schema.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.attribute-schema.validation.enabled | Boolean | true | enabled gates the real client. |
oauthy.identity.attribute-schema.validation.product-api-base-url | String | "http://thoryn-product-api:8082" | In-cluster product-api Service base URL. |
oauthy.identity.attribute-schema.validation.request-timeout | Duration | Duration.ofSeconds(5) | Connect + read timeout for the validate call (CLAUDE.md 5s HTTP-to-service ceiling). |
oauthy.identity.bot-detection
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/bot/BotDetectionProperties.kt
SSO-2616 — deploy-time (NON per-tenant) configuration for the bot-detection challenge integration.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.bot-detection.enabled | Boolean | true | Platform kill-switch. |
oauthy.identity.bot-detection.siteverify-url | String | DEFAULT_SITEVERIFY_URL | Cloudflare Turnstile server-side siteverify endpoint. |
oauthy.identity.bot-detection.verify-timeout | Duration | Duration.ofSeconds(5) | Bound on the siteverify call. |
oauthy.identity.bot-detection.fail-open-on-vendor-outage | Boolean | true | Vendor-outage posture. |
oauthy.identity.client-email-bases
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/email/ClientEmailBaseProperties.kt
SSO-1787: operator-controlled, per-client override for the base URL the password-reset and email-verification email links are built from.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.client-email-bases.bases | Map<String, String> | (empty) | Map of client_id → public base URL (scheme://host[:port]) for that client's email links. |
oauthy.identity.client-ip
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/web/ClientIpResolutionProperties.kt
SSO-2215 (Item 1): configuration for TrustedClientIpResolver.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.client-ip.trusted-proxy-count | Int | 1 | Number of trusted reverse proxies that sit in front of identity-service. |
oauthy.identity.consent
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/tou/ProductApiConsentClientProperties.kt
SSO-2563 (C4, epic SSO-2559) — configuration for ProductApiConsentClient, the identity→product-api seam that (a) enumerates the tenant/environment's active consent-purpose registry and (b) records an end-user's purpose-consent grant duri...
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.consent.product-api-base-url | String | "http://thoryn-product-api:8082" | In-cluster product-api Service base URL. |
oauthy.identity.consent.request-timeout | Duration | Duration.ofSeconds(5) | Connect + read timeout for the consent calls (CLAUDE.md 5s HTTP-to-service ceiling). |
oauthy.identity.credential-stuffing
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/credentialstuffing/CredentialStuffingProperties.kt
SSO-71: configuration for credential-stuffing velocity detection on the login endpoint.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.credential-stuffing.enabled | Boolean | false | Master switch. Defaults to false (opt-in per environment). |
oauthy.identity.credential-stuffing.per-ip-failure-threshold | Int | DEFAULT_PER_IP_THRESHOLD | Number of failed logins from a single source IP within perIpWindow that trips the per-IP credential-stuffing signal. |
oauthy.identity.credential-stuffing.per-ip-window | Duration | DEFAULT_PER_IP_WINDOW | Rolling window for the per-IP failed-login counter. |
oauthy.identity.credential-stuffing.per-ip-reputation-failure-threshold | Int | DEFAULT_PER_IP_REPUTATION_THRESHOLD | SSO-2046: the lowered per-IP failure threshold applied when the source IP carries a known bad reputation (today: a Tor exit node, per the com.devnow.oauthy.identity.reputation.IpReputationService feed). |
oauthy.identity.credential-stuffing.per-account-distinct-ip-threshold | Int | DEFAULT_PER_ACCOUNT_DISTINCT_IP_THRESHOLD | Number of distinct source IPs that must fail against one account within perAccountWindow to trip the per-account signal. |
oauthy.identity.credential-stuffing.per-account-window | Duration | DEFAULT_PER_ACCOUNT_WINDOW | Rolling window for the per-account distinct-IP set. |
oauthy.identity.credential-stuffing.soft-block-base-duration | Duration | DEFAULT_SOFT_BLOCK_BASE | Base temporary soft-block duration applied to an IP on its first per-IP breach. |
oauthy.identity.credential-stuffing.soft-block-max-duration | Duration | DEFAULT_SOFT_BLOCK_MAX | Ceiling on the escalated per-IP soft-block duration. |
oauthy.identity.default-tenant-migration
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/defaulttenant/DefaultTenantMigrationProperties.kt
SSO-1979 (epic SSO-1977: deprecate the shared default tenant) — the master gate for the S2 re-key machinery.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.default-tenant-migration.enabled | Boolean | false | true activates the lazy-trickle-at-login re-key; false (default) makes the whole seam inert. |
oauthy.identity.email-templates
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/emailtemplates/EmailTemplateProperties.kt
SSO-1898: size caps for tenant-supplied email-template overrides.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.email-templates.max-subject-chars | Int | 998 | Maximum length (in characters) of a customized subject line. |
oauthy.identity.email-templates.max-body-bytes | Int | 64 * 1024 | Maximum size (in UTF-8 bytes) of a customized HTML body. |
oauthy.identity.erasure
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/gdpr/ProductApiErasureClientProperties.kt
SSO-2511 — configuration for ProductApiErasureClient, the identity→product-api seam that opens a two-phase conditional-erasure request when a user erases their own account (DELETE /account/erase).
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.erasure.product-api-base-url | String | "http://thoryn-product-api:8082" | In-cluster product-api Service base URL. |
oauthy.identity.erasure.request-timeout | Duration | Duration.ofSeconds(5) | Connect + read timeout for the erasure-open call (CLAUDE.md 5s HTTP-to-service ceiling). |
oauthy.identity.geo-blocking
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/geoblocking/GeoBlockingProperties.kt
SSO-2042: operator-level configuration for geo-blocking login enforcement.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.geo-blocking.enabled | Boolean | true | Master switch. true (default) → the tenant's stored policy is honoured. |
oauthy.identity.geo-blocking.fail-open-on-unresolved | Boolean | true | What to do when the login IP cannot be resolved to a country (a private / loopback IP, or a public IP the bundled GeoLite2-Country dataset does not map). |
oauthy.identity.hooks.delivery-report
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/hooks/HookDeliveryReportProperties.kt
SSO-1985 — config for the inline-stage delivery-report outbox + poller.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.hooks.delivery-report.enabled | Boolean | true | When false, reports are neither enqueued nor delivered (test / opt-out). |
oauthy.identity.hooks.delivery-report.endpoint | String | "http://thoryn-product-api:8082/admin/hooks/internal/delivery-reports" | product-api's in-cluster delivery-report ingest URL (Service DNS, not public ingress). |
oauthy.identity.hooks.delivery-report.token-file | String | "/var/run/secrets/tokens/audit-emitter" | Projected SA token file (audience product-api) — reuses the audit-emitter volume. |
oauthy.identity.hooks.delivery-report.batch-size | Int | 32 | Rows drained per poll tick. |
oauthy.identity.hooks.delivery-report.max-attempts | Int | 8 | Max delivery attempts before the report is dropped (dead-lettered). |
oauthy.identity.hooks.delivery-report.max-backoff | Duration | Duration.ofMinutes(5) | Backoff ceiling: next_attempt_at = now + min(maxBackoff, 2^attempts) s. |
oauthy.identity.hooks.delivery-report.poll-interval | Duration | Duration.ofSeconds(5) | Poll cadence. |
oauthy.identity.hooks.delivery-report.block-timeout | Duration | Duration.ofSeconds(5) | Reactive→blocking / HTTP ceiling (CLAUDE.md SSO-771). |
oauthy.identity.hooks.registration-pre-create
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/hooks/RegistrationHookProperties.kt
SSO-1957 (Actions/Hooks H3) — engine config for the registration.pre-create inline stage in identity-service.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.hooks.registration-pre-create.default-budget | Duration | Duration.ofMillis(3000) | Applied when the mirrored hook carries no timeoutMs. |
oauthy.identity.hooks.registration-pre-create.hard-cap | Duration | Duration.ofMillis(5000) | Absolute ceiling any per-hook timeoutMs is clamped to (SSO-771 ≤ 5 s). |
oauthy.identity.hooks.registration-pre-create.max-request-bytes | Int | 64 * 1024 | Max request body bytes sent to the tenant endpoint (DoS bound). |
oauthy.identity.hooks.registration-pre-create.max-response-bytes | Int | 64 * 1024 | Max response body bytes read back from the tenant endpoint (DoS bound). |
oauthy.identity.hooks.registration-pre-create.max-attribute-chars | Int | 256 | Per-augmented-attribute character cap after merge (DoS / abuse bound). |
oauthy.identity.hooks.user-created
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/hooks/UserCreatedEventProperties.kt
SSO-1957 (Actions/Hooks H3) — config for the user.created event outbox + poller.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.hooks.user-created.enabled | Boolean | true | When false, events are neither enqueued nor delivered (test / opt-out). |
oauthy.identity.hooks.user-created.endpoint | String | "http://thoryn-product-api:8082/admin/hooks/internal/events" | product-api's in-cluster ingest URL (Service DNS, not the public ingress). |
oauthy.identity.hooks.user-created.token-file | String | "/var/run/secrets/tokens/audit-emitter" | Projected SA token file (audience product-api) — reuses the audit-emitter volume. |
oauthy.identity.hooks.user-created.batch-size | Int | 32 | Rows drained per poll tick. |
oauthy.identity.hooks.user-created.max-attempts | Int | 8 | Max delivery attempts before the event is dropped (dead-lettered). |
oauthy.identity.hooks.user-created.max-backoff | Duration | Duration.ofMinutes(5) | Backoff ceiling: next_attempt_at = now + min(maxBackoff, 2^attempts) s. |
oauthy.identity.hooks.user-created.poll-interval | Duration | Duration.ofSeconds(5) | Poll cadence. |
oauthy.identity.hooks.user-created.block-timeout | Duration | Duration.ofSeconds(5) | Reactive→blocking / HTTP ceiling (CLAUDE.md SSO-771). |
oauthy.identity.hub-consent
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/consent/HubConsentClientProperties.kt
SSO-2564 (C5, epic SSO-2559) — configuration for HubConsentClient, the identity→hub seam that reads and withdraws an end-user's OAuth-client consents for the "manage my consents" account page.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.hub-consent.hub-base-url | String | "http://thoryn-hub:8080" | In-cluster hub Service base URL. |
oauthy.identity.hub-consent.sa-token-path | String | "/var/run/secrets/tokens/hub-internal-auth" | On-disk path of identity-service's projected SA token for the identity → hub channel (audience hub-internal-auth). |
oauthy.identity.hub-consent.request-timeout | Duration | Duration.ofSeconds(5) | Connect + read timeout (CLAUDE.md 5s HTTP-to-service ceiling). |
oauthy.identity.impersonation-notification
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/impersonation/ImpersonationNotificationProperties.kt
SSO-2608 (epic SSO-2594, ADR 2026-08-17-user-impersonation-trust-model.md §7) — configuration for the ImpersonationNotificationEmailSender that emails an impersonated user "your account was accessed by support".
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.impersonation-notification.enabled | Boolean | true | Master switch. When false, the sender returns immediately without dispatching. |
oauthy.identity.impersonation-notification.from-address | String | "no-reply@thoryn.io" | From address for the notification. |
oauthy.identity.impersonation-notification.public-base-url | String | "https://stg.thoryn.org" | Public origin for the optional "review your account activity" link. |
oauthy.identity.import.jobs
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/users/importjob/BulkImportJobProperties.kt
SSO-1906: configuration for the asynchronous bulk user-import job surface.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.import.jobs.max-rows | Int | 10_000 | Upper bound on rows per asynchronous job. |
oauthy.identity.import.jobs.chunk-size | Int | 100 | Rows imported per progress-update slice. |
oauthy.identity.import.jobs.jobs-per-tick | Int | 3 | Pending jobs drained per poller tick. |
oauthy.identity.import.jobs.max-row-errors | Int | 500 | Cap on persisted per-row errors per job. |
oauthy.identity.import.jobs.max-attempts | Int | 5 | Attempts before a job that keeps failing transiently (e.g. |
oauthy.identity.import.jobs.stale-after | Duration | Duration.ofMinutes(30) | An in_progress job older than this is presumed orphaned by a dead runner and re-queued. |
oauthy.identity.import.jobs.transit-key | String | "identity-bulk-import" | Vault Transit key the payload envelope is encrypted against. |
oauthy.identity.impossible-travel
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/risk/ImpossibleTravelProperties.kt
SSO-72: configuration for the speed-based impossible-travel detector.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.impossible-travel.enabled | Boolean | true | Master enable flag for the speed-based detector. |
oauthy.identity.impossible-travel.max-kmh | Double | 1000.0 | Maximum plausible travel speed in km/h. |
oauthy.identity.impossible-travel.min-distance-km | Double | 100.0 | Minimum great-circle distance (km) between the two sign-in locations required before the speed check is even considered. |
oauthy.identity.impossible-travel-response
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/risk/response/ImpossibleTravelResponseProperties.kt
SSO-2041: operator-level configuration for the impossible-travel enforcement response.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.impossible-travel-response.enabled | Boolean | true | Master switch. true (default) → the tenant's stored response policy is honoured. |
oauthy.identity.internal-auth.k8s
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/internalauth/InternalAuthK8sProperties.kt
SSO-1792 — configuration for the secret-less S2S credential-validation channel (POST /internal/auth/validate).
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.internal-auth.k8s.enabled | Boolean | false | Gate for the whole channel. |
oauthy.identity.internal-auth.k8s.issuer | String | "https://kubernetes.default.svc.cluster.local" | Expected iss claim — the cluster SA issuer (SSO-1477). |
oauthy.identity.internal-auth.k8s.jwks-uri | String | "https://kubernetes.default.svc/openid/v1/jwks" | In-cluster OIDC JWKS address the decoder fetches the cluster keys from. |
oauthy.identity.internal-auth.k8s.audience | String | "identity-internal-auth" | Audience the hub's credential-validation projected token is pinned to (identity-internal-auth). |
oauthy.identity.internal-auth.k8s.allowed-sub | String | "^system:serviceaccount:thoryn:thoryn-hub-(audit-emitter|workload)$" | SSO-1790 anchored caller allow-list, a SINGLE string in the identity-service config shape (the shared factory takes a List<String>; see toValidationProperties). |
oauthy.identity.internal-auth.k8s.ca-path | String | "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" | Cluster CA bundle path for the JWKS TLS trust (SSO-1468). |
oauthy.identity.internal-auth.k8s.token-path | String | "/var/run/secrets/kubernetes.io/serviceaccount/token" | Projected SA token presented as a Bearer on the JWKS fetch (SSO-1471). |
oauthy.identity.internal-auth.k8s.connect-timeout | Duration | Duration.ofSeconds(2) | Connect timeout for the JWKS fetch (SSO-1468 blast-radius bound). |
oauthy.identity.internal-auth.k8s.read-timeout | Duration | Duration.ofSeconds(2) | Read timeout for the JWKS fetch (SSO-1468 blast-radius bound). |
oauthy.identity.invitations
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/invitations/InvitationProperties.kt
SSO-65: configuration for the admin user-invitation flow.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.invitations.site-origin | String | "https://thoryn.org" | Public origin of the marketing site / console that hosts the invitation landing page. |
oauthy.identity.invitations.token-ttl | Duration | Duration.ofDays(7) | Default TTL for a freshly-issued invitation. |
oauthy.identity.invitations.from-address | String | "no-reply@thoryn.io" | From address for outbound invitation mail. |
oauthy.identity.invitations.federated-accept
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/invitations/federated/FederatedInvitationBeginProperties.kt
SSO-2399 (slice 4b of SSO-2384 / D2 federated-invitation-accept) — configuration for the front door of the federated-invitation-accept flow: identity-service's POST /invitations/{token}/federated/begin (FederatedInvitationBeginController).
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.invitations.federated-accept.hub-base-url | String | "http://thoryn-hub:8080" | In-cluster base URL of the authorization hub, for the identity → hub mint call (POST /internal/account-link-intents). |
oauthy.identity.invitations.federated-accept.sa-token-path | String | "/var/run/secrets/tokens/hub-internal-auth" | On-disk path of identity-service's projected Kubernetes ServiceAccount token for the identity → hub mint channel (audience hub-internal-auth), mounted by the chart at /var/run/secrets/tokens/hub-internal-auth (a second serviceAccountToke... |
oauthy.identity.invitations.federated-accept.allowed-return-origins | List<String> | (empty) | Open-redirect allowlist for the accept-page returnUri the caller supplies. |
oauthy.identity.ip-reputation
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/reputation/IpReputationProperties.kt
SSO-2046: configuration for the IP-reputation feed that lowers the SSO-71 credential-stuffing per-IP threshold for a known-bad-reputation source IP.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.ip-reputation.enabled | Boolean | false | Master switch. Defaults to false (opt-in per environment). |
oauthy.identity.ip-reputation.tor-exit-list-url | String | DEFAULT_TOR_EXIT_LIST_URL | Authoritative, free source for the Tor exit-node list — the Tor Project's published bulk exit list (one IP per line; # comments and blank lines are ignored). |
oauthy.identity.ip-reputation.refresh-interval | Duration | DEFAULT_REFRESH_INTERVAL | How often the scheduled fetch refreshes the list. |
oauthy.identity.ip-reputation.feed-ttl | Duration | DEFAULT_FEED_TTL | TTL applied to the stored feed. |
oauthy.identity.ip-reputation.request-timeout | Duration | DEFAULT_REQUEST_TIMEOUT | Connect + read timeout for the outbound fetch. |
oauthy.identity.ip-reputation.max-entries | Int | DEFAULT_MAX_ENTRIES | Defensive cap on how many entries a single refresh will store — bounds the blast radius of a malformed or hostile oversized response. |
oauthy.identity.lockout
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/lockout/AccountLockoutProperties.kt
SSO-1895: tenant-configurable policy for the per-account password-failure lockout.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.lockout.enabled | Boolean | true | Master switch. When false the lockout is inert: failures are never counted, accounts are never locked, and AccountLockoutService short- circuits every call. |
oauthy.identity.lockout.threshold | Int | DEFAULT_THRESHOLD | Platform-default consecutive-failure threshold. |
oauthy.identity.lockout.cooldown | Duration | DEFAULT_COOLDOWN | Platform-default lock duration once the threshold is reached. |
oauthy.identity.lockout.failure-window | Duration | DEFAULT_COOLDOWN | How long the consecutive-failure counter itself survives without a new failure. |
oauthy.identity.lockout.tenant-overrides | Map<String, TenantLockoutPolicy> | (empty) | Per-tenant overrides keyed by tenant_id. |
oauthy.identity.login-flow
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/loginflow/LoginFlowProperties.kt
SSO-2334: configuration for the login-flow execution engine (epic SSO-1889, ADR 2026-08-05-login-flow-model-and-execution-engine.md).
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.login-flow.mode | LoginFlowMode | LoginFlowMode.OFF | the engine's runtime mode on the native login path. |
oauthy.identity.magic-code
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/magiccode/MagicCodeProperties.kt
SSO-2595 (epic SSO-2581): configuration for the magic-CODE (passwordless 6-digit email OTP) sign-in path — the WorkOS-style sibling of the SSO-57 magic-LINK flow.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.magic-code.enabled | Boolean | true | Whether the magic-code affordance is enabled globally. |
oauthy.identity.magic-code.code-length | Int | 6 | Number of digits in the emailed code. |
oauthy.identity.magic-code.token-ttl | Duration | Duration.ofMinutes(10) | How long a freshly-minted magic-code is valid. |
oauthy.identity.magic-code.max-attempts | Int | 5 | Maximum number of verify attempts against a single issued code before it is voided. |
oauthy.identity.magic-code.from-address | String | "no-reply@thoryn.io" | From address for outbound magic-code mail. |
oauthy.identity.magic-link
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/magiclink/MagicLinkProperties.kt
SSO-57: configuration for the magic-link (passwordless) sign-in path.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.magic-link.public-base-url | String | "http://localhost:9100" | Public origin where this identity-service is reachable from the user's browser. |
oauthy.identity.magic-link.token-ttl | Duration | Duration.ofMinutes(15) | How long a freshly-minted magic-link token is valid. |
oauthy.identity.magic-link.from-address | String | "no-reply@thoryn.io" | From address for outbound magic-link mail. |
oauthy.identity.magic-link.enabled | Boolean | true | Whether the magic-link affordance is enabled globally. |
oauthy.identity.magic-link.cross-device.code-length | Int | 6 | Digits in the cross-device continuation code. |
oauthy.identity.magic-link.cross-device.code-ttl | Duration | Duration.ofMinutes(10) | How long a cross-device continuation code is valid. |
oauthy.identity.magic-link.cross-device.max-attempts | Int | 5 | Maximum wrong-code redeem attempts against a single continuation code before it is voided. |
oauthy.identity.migration.import
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/migration/importjob/MigrationImportJobProperties.kt
SSO-2358 — configuration for the eager Auth0 profile-import job surface.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.migration.import.page-size | Int | 50 | Profiles fetched per page from the source's export API. |
oauthy.identity.migration.import.jobs-per-tick | Int | 2 | Pending jobs claimed + processed per poller tick. |
oauthy.identity.migration.import.max-pages-per-claim | Int | 10 | Pages drained per claim before the job is checkpointed back to pending for a later tick. |
oauthy.identity.migration.import.max-attempts | Int | 5 | Consecutive transient failures (source unreachable / Management token unobtainable) before a job flips to failed instead of re-queueing. |
oauthy.identity.migration.import.stale-after | Duration | Duration.ofMinutes(15) | An in_progress job older than this is presumed orphaned by a dead runner and re-queued. |
oauthy.identity.new-device
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/risk/NewDeviceProperties.kt
SSO-2044: configuration for the new-device login detector.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.new-device.enabled | Boolean | true | Master enable flag for the new-device detector. |
oauthy.identity.notifications.new-country
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/notifications/NewCountryLoginProperties.kt
SSO-891 configuration for the "login from new country" notification.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.notifications.new-country.enabled | Boolean | true | Master switch. When false, the NewCountryLoginNotifier returns immediately without sending anything. |
oauthy.identity.notifications.new-country.from-address | String | "no-reply@thoryn.io" | From address for the outbound notification. |
oauthy.identity.notifications.new-country.public-base-url | String | "https://stg.thoryn.org" | Public origin used to build the "wasn't me" link. |
oauthy.identity.notifications.new-country.suppression-window | Duration | Duration.ofHours(24) | 24h per-(user, country) suppression window — a second login from the same country inside this window does not fire a duplicate email. |
oauthy.identity.notifications.new-country.wasnt-me-ttl | Duration | Duration.ofHours(24) | TTL for the single-use "wasn't me" link. |
oauthy.identity.password-reset
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/passwordreset/PasswordResetApiProperties.kt
SSO-1022: configuration for the JSON /password/reset/{request,confirm} endpoints.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.password-reset.site-origin | String | "https://thoryn.org" | Public origin of the marketing site that hosts the /reset-password?token=... |
oauthy.identity.password-reset.token-ttl | Duration | Duration.ofMinutes(15) | How long a freshly-minted reset token is valid. |
oauthy.identity.password-reset.from-address | String | "no-reply@thoryn.io" | From address for outbound password-reset mail. |
oauthy.identity.scim.directory-bearer
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/scim/directory/DirectoryScimBearerAuthProperties.kt
SSO-2490 — configuration for enforcing the inbound Directory-Sync SCIM bearer at the SCIM ingest edge.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.scim.directory-bearer.enabled | Boolean | true | Master switch. Default on: the enforcement only activates on the per-directory ingest path (/scim/v2/directories/[]), which carries no traffic until a tenant configures a Directory-Sync connector, so enabling it by default changes no exi... |
oauthy.identity.scim.directory-bearer.product-api-base-url | String | "http://thoryn-product-api:8082" | In-cluster product-api Service base URL (matches the SCIM-groups facade / audit-emitter). |
oauthy.identity.scim.directory-bearer.request-timeout | Duration | Duration.ofSeconds(5) | Connect + read timeout for the resolve / record-push S2S calls (CLAUDE.md 5s HTTP-to-service ceiling). |
oauthy.identity.scim.org-unification
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/scim/groups/ScimOrgUnificationProperties.kt
Configuration for the SCIM-Groups unification facade (SSO-1959).
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.scim.org-unification.product-api-base-url | String | "http://thoryn-product-api:8082" | In-cluster product-api Service base URL (matches the audit-emitter's thoryn-product-api:8082). |
oauthy.identity.scim.org-unification.request-timeout | Duration | Duration.ofSeconds(5) | Connect + read timeout for the facade HTTP calls (CLAUDE.md 5s HTTP-to-service ceiling). |
oauthy.identity.scim.org-unification.backfill-enabled | Boolean | true | Whether the one-time idempotent backfill runs on startup (reads the legacy organisations / organisation_memberships and upserts them into the product-api SoR). |
oauthy.identity.security-incident-email
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/security/SecurityIncidentEmailProperties.kt
SSO-1109: configuration for the SecurityIncidentEmailSender that ships a "refresh-token theft detected" notification when the hub's SecurityEventForwarder POSTs a refresh-token-replay event to POST /internal/security-events.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.security-incident-email.enabled | Boolean | true | Master switch. When false, the sender returns immediately without dispatching. |
oauthy.identity.security-incident-email.from-address | String | "no-reply@thoryn.io" | From address for the outbound notification. |
oauthy.identity.security-incident-email.public-base-url | String | "https://stg.thoryn.org" | Public origin used to build the "wasn't me" link. |
oauthy.identity.security-incident-email.suppression-window | Duration | Duration.ofHours(1) | Per-user suppression window. |
oauthy.identity.security-incident-email.wasnt-me-ttl | Duration | Duration.ofDays(7) | SSO-1111: TTL for the single-use "wasn't me" link embedded in the refresh-token-theft email. |
oauthy.identity.security-policy
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/securitypolicy/SecurityPolicyProperties.kt
SSO-1930: platform security floor + defaults for the tenant credential-security policy (ADR 2026-07-14-tenant-security-policy-facade.md §1).
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.security-policy.floor.lockout-threshold-min | Int | 3 | |
oauthy.identity.security-policy.floor.lockout-threshold-max | Int | 10 | |
oauthy.identity.security-policy.floor.lockout-threshold-default | Int | 5 | |
oauthy.identity.security-policy.floor.lockout-cooldown-seconds-min | Int | 60 | |
oauthy.identity.security-policy.floor.lockout-cooldown-seconds-default | Int | 900 | |
oauthy.identity.security-policy.floor.password-min-length-min | Int | 8 | |
oauthy.identity.security-policy.floor.password-min-length-default | Int | 8 | |
oauthy.identity.security-policy.floor.password-require-complexity-default | Boolean | false | |
oauthy.identity.security-policy.floor.password-require-uppercase-default | Boolean | false | |
oauthy.identity.security-policy.floor.password-require-lowercase-default | Boolean | false | |
oauthy.identity.security-policy.floor.password-require-number-default | Boolean | false | |
oauthy.identity.security-policy.floor.password-require-special-default | Boolean | false | |
oauthy.identity.security-policy.floor.password-history-depth-min | Int | 0 | |
oauthy.identity.security-policy.floor.password-history-depth-max | Int | 24 | |
oauthy.identity.security-policy.floor.password-history-depth-default | Int | 0 | |
oauthy.identity.security-policy.floor.password-min-strength-min | Int | 0 | |
oauthy.identity.security-policy.floor.password-min-strength-max | Int | 4 | |
oauthy.identity.security-policy.floor.password-min-strength-default | Int | 0 | |
oauthy.identity.security-policy.floor.max-concurrent-sessions-min | Int | 1 | |
oauthy.identity.security-policy.floor.max-concurrent-sessions-max | Int | 50 | |
oauthy.identity.security-policy.floor.max-concurrent-sessions-default | Int | 10 | |
oauthy.identity.security-policy.floor.self-signup-enabled-default | Boolean | true | |
oauthy.identity.security-policy.floor.invite-only-default | Boolean | false | |
oauthy.identity.security-policy.floor.require-verified-email-default | Boolean | false | |
oauthy.identity.security-policy.floor.trusted-device-enabled-default | Boolean | false | |
oauthy.identity.security-policy.floor.trusted-device-max-ttl-secs-min | Int | 3_600 | |
oauthy.identity.security-policy.floor.trusted-device-max-ttl-secs-max | Int | 2_592_000 | |
oauthy.identity.security-policy.floor.trusted-device-max-ttl-secs-default | Int | 2_592_000 | |
oauthy.identity.security-policy.floor.session-idle-timeout-secs-min | Int | 60 | |
oauthy.identity.security-policy.floor.session-idle-timeout-secs-max | Int | 2_592_000 | |
oauthy.identity.security-policy.floor.session-absolute-timeout-secs-min | Int | 300 | |
oauthy.identity.security-policy.floor.session-absolute-timeout-secs-max | Int | 7_776_000 | |
oauthy.identity.security-policy.breach-check.enabled | Boolean | true | Whether a password offered at registration / password-reset is checked against the HIBP breach corpus. |
oauthy.identity.security-policy.breach-check.fail-open | Boolean | true | What to do when HIBP cannot be reached (timeout / 5xx / DNS / SSRF guard). |
oauthy.identity.sessions
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/sessions/SessionLimitProperties.kt
SSO-890: configuration for the per-user concurrent-session cap.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.sessions.max-per-user | Int | 10 | Maximum number of concurrent active sessions per user. |
oauthy.identity.sign-in-attempts
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/signin/SignInAttemptProperties.kt
SSO-1908: configuration for the sign_in_attempt capture table.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.sign-in-attempts.retention | Duration | Duration.ofDays(365) | How long to retain sign_in_attempt rows. |
oauthy.identity.sign-in-attempts.factor-ttl | Duration | Duration.ofMinutes(15) | TTL of the transient last-login-factor stash in Redis (LastLoginFactorStore). |
oauthy.identity.social
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/social/runtime/SocialRuntimeProperties.kt
SSO-2611 (epic SSO-2606): configuration for the social-login OAuth RUNTIME — the engine that turns a per-tenant com.devnow.oauthy.identity.social.SocialConnectorConfigEntity row into an actual "Sign in with Google" OAuth dance on the hos...
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.social.enabled | Boolean | true | Global feature switch for the social-login runtime. |
oauthy.identity.social.redirect-base-url | String | "" | Browser-facing public origin the provider redirects back to. |
oauthy.identity.social.state-ttl | Duration | Duration.ofMinutes(10) | How long a pending authorize state lives in Redis before it expires. |
oauthy.identity.social.http-timeout | Duration | Duration.ofSeconds(5) | Bounded HTTP timeout for every outbound provider call (discovery, token, userinfo, JWKS). |
oauthy.identity.social.google.issuer | String | "" | |
oauthy.identity.social.google.authorization-endpoint | String | "" | |
oauthy.identity.social.google.token-endpoint | String | "" | |
oauthy.identity.social.google.jwks-uri | String | "" | |
oauthy.identity.social.google.user-info-endpoint | String | "" | |
oauthy.identity.social.microsoft.issuer | String | "" | |
oauthy.identity.social.microsoft.authorization-endpoint | String | "" | |
oauthy.identity.social.microsoft.token-endpoint | String | "" | |
oauthy.identity.social.microsoft.jwks-uri | String | "" | |
oauthy.identity.social.microsoft.user-info-endpoint | String | "" | |
oauthy.identity.social.github.issuer | String | "" | |
oauthy.identity.social.github.authorization-endpoint | String | "" | |
oauthy.identity.social.github.token-endpoint | String | "" | |
oauthy.identity.social.github.jwks-uri | String | "" | |
oauthy.identity.social.github.user-info-endpoint | String | "" | |
oauthy.identity.social.gitlab.issuer | String | "" | |
oauthy.identity.social.gitlab.authorization-endpoint | String | "" | |
oauthy.identity.social.gitlab.token-endpoint | String | "" | |
oauthy.identity.social.gitlab.jwks-uri | String | "" | |
oauthy.identity.social.gitlab.user-info-endpoint | String | "" | |
oauthy.identity.social.salesforce.issuer | String | "" | |
oauthy.identity.social.salesforce.authorization-endpoint | String | "" | |
oauthy.identity.social.salesforce.token-endpoint | String | "" | |
oauthy.identity.social.salesforce.jwks-uri | String | "" | |
oauthy.identity.social.salesforce.user-info-endpoint | String | "" | |
oauthy.identity.social.intuit.issuer | String | "" | |
oauthy.identity.social.intuit.authorization-endpoint | String | "" | |
oauthy.identity.social.intuit.token-endpoint | String | "" | |
oauthy.identity.social.intuit.jwks-uri | String | "" | |
oauthy.identity.social.intuit.user-info-endpoint | String | "" | |
oauthy.identity.social.xero.issuer | String | "" | |
oauthy.identity.social.xero.authorization-endpoint | String | "" | |
oauthy.identity.social.xero.token-endpoint | String | "" | |
oauthy.identity.social.xero.jwks-uri | String | "" | |
oauthy.identity.social.xero.user-info-endpoint | String | "" | |
oauthy.identity.social.linkedin.issuer | String | "" | |
oauthy.identity.social.linkedin.authorization-endpoint | String | "" | |
oauthy.identity.social.linkedin.token-endpoint | String | "" | |
oauthy.identity.social.linkedin.jwks-uri | String | "" | |
oauthy.identity.social.linkedin.user-info-endpoint | String | "" | |
oauthy.identity.social.apple.issuer | String | "" | |
oauthy.identity.social.apple.authorization-endpoint | String | "" | |
oauthy.identity.social.apple.token-endpoint | String | "" | |
oauthy.identity.social.apple.jwks-uri | String | "" | |
oauthy.identity.social.apple.user-info-endpoint | String | "" | |
oauthy.identity.social.slack.issuer | String | "" | |
oauthy.identity.social.slack.authorization-endpoint | String | "" | |
oauthy.identity.social.slack.token-endpoint | String | "" | |
oauthy.identity.social.slack.jwks-uri | String | "" | |
oauthy.identity.social.slack.user-info-endpoint | String | "" | |
oauthy.identity.social.vercel.issuer | String | "" | |
oauthy.identity.social.vercel.authorization-endpoint | String | "" | |
oauthy.identity.social.vercel.token-endpoint | String | "" | |
oauthy.identity.social.vercel.jwks-uri | String | "" | |
oauthy.identity.social.vercel.user-info-endpoint | String | "" |
oauthy.identity.step-up.email-otp
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/stepup/StepUpChallengeProperties.kt
SSO-2083: platform-level configuration for the out-of-band email step-up challenge that lets identity-service genuinely challenge a FACTOR-LESS user on a high-risk sign-in.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.step-up.email-otp.enabled | Boolean | true | Master switch for the email-OTP step-up channel. |
oauthy.identity.step-up.email-otp.code-length | Int | 6 | Digits in the emailed code. |
oauthy.identity.step-up.email-otp.ttl | Duration | Duration.ofMinutes(10) | How long an issued code stays valid. |
oauthy.identity.step-up.email-otp.max-attempts | Int | 5 | Verification attempts allowed against one challenge before it is voided. |
oauthy.identity.step-up.email-otp.max-per-user-per-hour | Long | 5 | Challenges a single user may be issued per hour (Bucket4j + Redis). |
oauthy.identity.step-up.email-otp.max-per-ip-per-hour | Long | 20 | Challenges a single source IP may trigger per hour (Bucket4j + Redis). |
oauthy.identity.step-up.email-otp.from-address | String | "no-reply@thoryn.io" | From-address for the challenge email, mirroring the per-sender convention the other identity-service senders use (magic-link, password-reset, verification). |
oauthy.identity.tenant-facade.k8s
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/internaltenant/TenantFacadeK8sProperties.kt
SSO-1928 — configuration for the secret-less S2S auth on the tenant-parameterized facade surface (/internal/tenants/[]), consumed by product-api's login-experience / security-policy / migration-source / invitation / user-management facades.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.tenant-facade.k8s.enabled | Boolean | false | Gate for the whole channel. |
oauthy.identity.tenant-facade.k8s.issuer | String | "https://kubernetes.default.svc.cluster.local" | Expected iss claim — the cluster SA issuer (SSO-1477). |
oauthy.identity.tenant-facade.k8s.jwks-uri | String | "https://kubernetes.default.svc/openid/v1/jwks" | In-cluster OIDC JWKS address the decoder fetches the cluster keys from. |
oauthy.identity.tenant-facade.k8s.audience | String | "identity-tenant-facade" | Audience product-api's facade projected token is pinned to (identity-tenant-facade). |
oauthy.identity.tenant-facade.k8s.allowed-sub | String | "^system:serviceaccount:thoryn:thoryn-product-api$" | Anchored (^…$) exact-match caller allow-list — product-api's ServiceAccount. |
oauthy.identity.tenant-facade.k8s.ca-path | String | "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" | Cluster CA bundle path for the JWKS TLS trust (SSO-1468). |
oauthy.identity.tenant-facade.k8s.token-path | String | "/var/run/secrets/kubernetes.io/serviceaccount/token" | Projected SA token presented as a Bearer on the JWKS fetch (SSO-1471). |
oauthy.identity.tenant-facade.k8s.connect-timeout | Duration | Duration.ofSeconds(2) | Connect timeout for the JWKS fetch (SSO-1468 blast-radius bound). |
oauthy.identity.tenant-facade.k8s.read-timeout | Duration | Duration.ofSeconds(2) | Read timeout for the JWKS fetch (SSO-1468 blast-radius bound). |
oauthy.identity.tenant-subdomain
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/branding/TenantSubdomainProperties.kt
SSO-2031 (Part B) — configuration for per-tenant identity-subdomain login resolution, mirroring the hub's per-tenant issuer host {slug}.hub.<platformDomain> (SSO-1517).
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.tenant-subdomain.base-domain | String | "" | the platform base domain under which per-tenant identity subdomains live — the value without the leading identity. |
oauthy.identity.tenant-subdomain.refresh-interval-millis | Long | DEFAULT_REFRESH_INTERVAL_MILLIS | the scheduled cadence (ms) at which IdentityTenantSlugRegistry reloads its trusted-tenant-slug snapshot. |
oauthy.identity.trusted-device
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/trusteddevice/TrustedDeviceProperties.kt
SSO-2634: platform-level (operator, NOT tenant-writable) configuration for the trusted-device MFA skip — cookie name, token entropy, and the TTL floor bounds.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.trusted-device.cookie-name | String | "THORYN_TRUSTED_DEVICE" | Name of the trusted-device cookie. |
oauthy.identity.trusted-device.token-bytes | Int | 32 | Number of random bytes in the opaque cookie token. |
oauthy.identity.user-metadata
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/users/service/UserMetadataProperties.kt
SSO-1894: configuration for the per-user metadata bags (app_metadata + user_metadata).
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.user-metadata.max-bytes-per-bag | Int | 32 * 1024 | Maximum size, in UTF-8 bytes of the compact JSON serialisation, of a single metadata bag. |
oauthy.identity.verification
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/verification/EmailVerificationProperties.kt
Configuration for the email-verification flow (SSO-911).
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.identity.verification.enabled | Boolean | true | Master switch. When false, registration succeeds without sending an email and the controller endpoints return 404. |
oauthy.identity.verification.token-ttl | Duration | Duration.ofHours(24) | How long the verification link is valid. |
oauthy.identity.verification.from-address | String | "no-reply@thoryn.io" | From address for outbound verification mail. |
oauthy.identity.verification.public-base-url | String | "https://stg.thoryn.org" | Public origin of the marketing site that hosts the verification landing page. |
oauthy.identity.verification.resend-rate-limit-per-hour | Int | 3 | Per-email cap on resend requests inside a sliding one-hour window. |
oauthy.risk
Owner: federation-members/identity-service · Source: servers/federation-members/identity-service/src/main/kotlin/com/devnow/oauthy/identity/risk/RiskProperties.kt
SSO-1318: configuration for the risk-signal engine.
| Property | Type | Default | Description |
|---|---|---|---|
oauthy.risk.hibp-api-base-url | String | "https://api.pwnedpasswords.com" | Base URL of the HIBP (HaveIBeenPwned) k-anonymity password-range API. |
oauthy.risk.hibp-cache-ttl | Duration | Duration.ofHours(24) | How long a positive HIBP result is cached per user+prefix in Redis. |
oauthy.risk.hibp-request-timeout | Duration | Duration.ofSeconds(2) | SSO-60: connect + read timeout for a single HIBP range call. |
oauthy.risk.impossible-travel-window | Duration | Duration.ofHours(2) | Window within which two sign-ins from geographically distant locations trigger the impossible-travel signal. |
oauthy.risk.impossible-travel-distance-km | Double | 500.0 | Minimum distance in kilometres between two sign-in countries' centroids required to fire the impossible-travel signal. |
oauthy.risk.unfamiliar-location-window | Duration | Duration.ofDays(90) | How far back to look when deciding whether a country/ASN is "unfamiliar" for a user. |
oauthy.risk.history-ttl | Duration | Duration.ofDays(90) | How long to retain rows in sign_in_history. |
Every property above is set as a YAML key under application.yml or, equivalently, as an environment variable using Spring's relaxed binding (oauthy.hub.platform-client-ids -> OAUTHY_HUB_PLATFORM_CLIENT_IDS). A _required_ default means the service will not start until the value is supplied.