# `Sigra.Config`
[🔗](https://github.com/sztheory/sigra/blob/v1.20.0/lib/sigra/config.ex#L1)

Configuration for Sigra authentication.

Sigra uses `NimbleOptions` for compile-time validated configuration with
auto-generated documentation. Only `:repo` and `:user_schema` are required;
all other options have secure, OWASP-grade defaults.

## Usage

    config = Sigra.Config.new!(
      repo: MyApp.Repo,
      user_schema: MyApp.Accounts.User
    )

## Options

* `:repo` (`t:atom/0`) - Required. The Ecto Repo module for database operations.

* `:user_schema` (`t:atom/0`) - Required. The Ecto schema module for users.

* `:otp_app` (`t:atom/0`) - The OTP application name. Used for config.exs convenience layer.

* `:secret_key_base` - The host app's secret key base. Required for JWT HS256 signing and token operations. The default value is `nil`.

* `:mailer` (`t:atom/0`) - The mailer module implementing `Sigra.Mailer` behaviour.

* `:email_module` - The generated email template module implementing `Sigra.EmailTemplates` behaviour. The default value is `nil`.

* `:password` (`t:keyword/0`) - Password hashing and validation options. The default value is `[]`.

  * `:min_length` (`t:pos_integer/0`) - Minimum password length. NIST SP 800-63B recommends at least 8. The default value is `8`.

  * `:max_length` (`t:pos_integer/0`) - Maximum password length. Set to 72 to match bcrypt's limit for migration compatibility. The default value is `72`.

  * `:hasher` (`t:atom/0`) - Module implementing the `Sigra.Hasher` behaviour. The default value is `Sigra.Hashers.Argon2`.

  * `:notify_on_change` (`t:boolean/0`) - Send notification email when password is changed. Default: true. The default value is `true`.

  * `:invalidate_sessions_on_change` (`t:boolean/0`) - Invalidate all other sessions on password change. Default: true. The default value is `true`.

* `:password_policy` (`t:keyword/0`) - Password validation policy options for `Sigra.PasswordPolicy`. The default value is `[]`.

  * `:min_length` (`t:pos_integer/0`) - Minimum password length. Default: 8 (NIST SP 800-63B). The default value is `8`.

  * `:max_bytes` (`t:pos_integer/0`) - Maximum password byte size. Default: 72 (bcrypt compatibility). The default value is `72`.

  * `:require_uppercase` (`t:boolean/0`) - Require at least one uppercase letter. Default: false. The default value is `false`.

  * `:require_digit` (`t:boolean/0`) - Require at least one digit. Default: false. The default value is `false`.

  * `:require_special` (`t:boolean/0`) - Require at least one special character. Default: false. The default value is `false`.

  * `:check_common` (`t:boolean/0`) - Check against the embedded common passwords list. Default: true. The default value is `true`.

  * `:check_breached` (`t:boolean/0`) - Check against the HIBP breached passwords API. Default: false. The default value is `false`.

  * `:password_max_age` - Maximum password age in seconds before forced rotation. Default: nil (disabled). The default value is `nil`.

* `:magic_link` (`t:keyword/0`) - Magic link authentication options. The default value is `[]`.

  * `:ttl` (`t:pos_integer/0`) - Magic link token TTL in seconds. Default: 600 (10 minutes). The default value is `600`.

  * `:max_requests` (`t:pos_integer/0`) - Maximum magic link requests within the rate limit window. Default: 3. The default value is `3`.

  * `:window_seconds` (`t:pos_integer/0`) - Rate limit window for magic link requests in seconds. Default: 900 (15 minutes). The default value is `900`.

* `:require_confirmation` (`t:boolean/0`) - Whether email confirmation is required before login. Default: false. The default value is `false`.

* `:session_ttl` (`t:pos_integer/0`) - Session time-to-live in seconds. Default: 5,184,000 (60 days). The default value is `5184000`.

* `:session` (`t:keyword/0`) - Session management options. The default value is `[]`.

  * `:remember_me_max_age` (`t:pos_integer/0`) - Max age for remember-me cookies in seconds. Default: 60 days (5,184,000s). The default value is `5184000`.

  * `:reissue_age` (`t:pos_integer/0`) - Age after which session tokens are reissued. Default: 7 days. The default value is `604800`.

  * `:store` (`t:atom/0`) - Module implementing the `Sigra.SessionStore` behaviour. The default value is `Sigra.SessionStores.Ecto`.

  * `:idle_timeout` (`t:pos_integer/0`) - Idle timeout in seconds. Default: 1800 (30 minutes). The default value is `1800`.

  * `:absolute_timeout` (`t:pos_integer/0`) - Absolute session timeout in seconds. Default: 86400 (24 hours). The default value is `86400`.

  * `:activity_update_threshold` (`t:pos_integer/0`) - Minimum seconds between last_active_at DB writes. Default: 300 (5 minutes). The default value is `300`.

  * `:sudo_timeout` (`t:pos_integer/0`) - Sudo mode window in seconds. Default: 300 (5 minutes). The default value is `300`.

  * `:session_schema` (`t:atom/0`) - The generated UserSession Ecto schema module.

* `:token_ttl` (`t:keyword/0`) - Token time-to-live values in seconds. The default value is `[]`.

  * `:confirm` (`t:pos_integer/0`) - Email confirmation token TTL. Default: 48 hours. The default value is `172800`.

  * `:reset_password` (`t:pos_integer/0`) - Password reset token TTL. Default: 1 hour. The default value is `3600`.

  * `:magic_link` (`t:pos_integer/0`) - Magic link token TTL. Default: 15 minutes. The default value is `900`.

  * `:email_change` (`t:pos_integer/0`) - Email change token TTL in seconds. Default: 24 hours. The default value is `86400`.

* `:rate_limiting` (`t:keyword/0`) - Rate limiting options. The default value is `[]`.

  * `:limiter` - Module implementing the `Sigra.RateLimiter` behaviour. Nil disables rate limiting. The default value is `nil`.

  * `:ip_limit` (`t:pos_integer/0`) - Maximum requests per IP within the window. Default: 10. The default value is `10`.

  * `:ip_window_ms` (`t:pos_integer/0`) - IP rate limiting window in milliseconds. Default: 60 seconds. The default value is `60000`.

  * `:account_limit` (`t:pos_integer/0`) - Maximum failed attempts per account before lockout. Default: 5. The default value is `5`.

* `:confirmation` (`t:keyword/0`) - Email confirmation options. The default value is `[]`.

  * `:unconfirmed_access` - Behavior for unconfirmed users. :allow_with_banner shows a reminder, :block prevents login. The default value is `:allow_with_banner`.

  * `:code_length` (`t:pos_integer/0`) - Length of the numeric confirmation code. Default: 6. The default value is `6`.

  * `:max_resends` (`t:pos_integer/0`) - Maximum confirmation resend requests per window. Default: 3. The default value is `3`.

  * `:resend_window_seconds` (`t:pos_integer/0`) - Rate limit window for confirmation resend in seconds. Default: 900 (15 minutes). The default value is `900`.

  * `:code_max_attempts` (`t:pos_integer/0`) - Maximum code entry attempts per window. Default: 5. The default value is `5`.

  * `:code_window_seconds` (`t:pos_integer/0`) - Rate limit window for code entry in seconds. Default: 900 (15 minutes). The default value is `900`.

* `:reset` (`t:keyword/0`) - Password reset options. The default value is `[]`.

  * `:max_requests` (`t:pos_integer/0`) - Maximum reset requests per email per window. Default: 3. The default value is `3`.

  * `:window_seconds` (`t:pos_integer/0`) - Rate limit window for reset requests in seconds. Default: 900 (15 minutes). The default value is `900`.

* `:email` (`t:keyword/0`) - Email delivery options. The default value is `[]`.

  * `:from_address` (`t:String.t/0`) - From address for transactional emails. Default derived from endpoint config.

  * `:delivery_mode` - Email delivery mode. :auto detects Oban presence. Default: :auto. The default value is `:auto`.

  * `:oban_queue` (`t:String.t/0`) - Oban queue name for async email delivery. Default: "sigra_mailer". The default value is `"sigra_mailer"`.

  * `:oban_concurrency` (`t:pos_integer/0`) - Maximum concurrent email delivery workers. Default: 10. The default value is `10`.

* `:lockout` (`t:keyword/0`) - Account lockout options. The default value is `[]`.

  * `:threshold` (`t:pos_integer/0`) - Failed attempts before lockout. Default: 5. The default value is `5`.

  * `:duration` (`t:pos_integer/0`) - Lockout duration in seconds. Default: 900 (15 minutes). The default value is `900`.

  * `:notify` (`t:boolean/0`) - Send lockout notification email. Default: true. The default value is `true`.

* `:geo_ip` (`t:keyword/0`) - GeoIP lookup options. The default value is `[]`.

  * `:module` - Module implementing Sigra.GeoIP behaviour. Default: nil (disabled). The default value is `nil`.

* `:suspicious_login` (`t:keyword/0`) - Suspicious login detection options. The default value is `[]`.

  * `:enabled` (`t:boolean/0`) - Enable suspicious login detection. Default: true. The default value is `true`.

  * `:notify` (`t:boolean/0`) - Send suspicious login notification email. Default: true. The default value is `true`.

* `:mfa` (`t:keyword/0`) - Multi-factor authentication options. The default value is `[]`.

  * `:enabled` (`t:boolean/0`) - Enable MFA support. Default: true. The default value is `true`.

  * `:totp_issuer` - TOTP issuer name for authenticator apps. Falls back to humanized otp_app. Default: nil. The default value is `nil`.

  * `:totp_drift_steps` (`t:non_neg_integer/0`) - TOTP drift window in 30-second steps. Default: 1. The default value is `1`.

  * `:backup_code_count` (`t:pos_integer/0`) - Number of backup codes generated per enrollment. Default: 8. The default value is `8`.

  * `:trust_enabled` (`t:boolean/0`) - Enable trust-this-browser cookies. Default: true. The default value is `true`.

  * `:trust_ttl` (`t:pos_integer/0`) - Trust cookie TTL in seconds (default 30 days). Default: 2,592,000. The default value is `2592000`.

  * `:lockout_threshold` (`t:pos_integer/0`) - Failed MFA attempts before lockout. Default: 5. The default value is `5`.

  * `:lockout_duration` (`t:pos_integer/0`) - MFA lockout duration in seconds (default 15 min). Default: 900. The default value is `900`.

  * `:pending_timeout` (`t:pos_integer/0`) - MFA pending session timeout in seconds (default 5 min). Default: 300. The default value is `300`.

  * `:show_trust_option` (`t:boolean/0`) - Show trust-this-browser checkbox on MFA challenge. Default: true. The default value is `true`.

* `:passkeys` (`t:keyword/0`) - Passkey (WebAuthn) options. The default value is `[]`.

  * `:enabled` (`t:boolean/0`) - Enable passkey support. Default: true. The default value is `true`.

  * `:passkey_primary_enabled` (`t:boolean/0`) - Enable passkey-primary login. Passkey MFA and enrollment are still controlled by :enabled. Default: false. The default value is `false`.

  * `:sign_count_policy` - Sign-count regression policy. Default: :warn to accommodate synced passkeys. The default value is `:warn`.

  * `:max_per_user` (`t:pos_integer/0`) - Maximum passkeys per user. Enforced atomically. Default: 10. The default value is `10`.

  * `:rp_id` - Relying party ID. Default: nil. The default value is `nil`.

  * `:rp_name` (`t:String.t/0`) - Relying party display name. Default: "Sigra". The default value is `"Sigra"`.

  * `:origin` - Relying party origin (https://...). Default: nil. The default value is `nil`.

  * `:attestation` - Attestation conveyance preference. Default: :none. The default value is `:none`.

  * `:user_verification` - User verification requirement. Default: :preferred. The default value is `:preferred`.

  * `:timeout_ms` (`t:pos_integer/0`) - Passkey ceremony timeout in milliseconds. Default: 60_000. The default value is `60000`.

  * `:ceremony_rate_limit` (`t:keyword/0`) - Per-user ceremony initiation rate limit. Default: 5 per 60_000ms. The default value is `[]`.

    * `:limit` (`t:pos_integer/0`) - Maximum ceremony initiations per user within the window. Default: 5. The default value is `5`.

    * `:window_ms` (`t:pos_integer/0`) - Ceremony initiation window in milliseconds. Default: 60_000. The default value is `60000`.

  * `:user_passkey_schema` - Generated host UserPasskey schema module. Default: nil. The default value is `nil`.

* `:oauth` (`t:keyword/0`) - OAuth / social login options. The default value is `[]`.

  * `:enabled` (`t:boolean/0`) - Master switch for OAuth. When false, OAuth routes are disabled and buttons hidden (D-63). The default value is `true`.

  * `:providers` (`t:keyword/0`) - Provider configurations. Each key is a provider atom, value is a keyword list with :client_id, :client_secret, :redirect_uri, and optional :strategy, :scopes. The default value is `[]`.

  * `:session_type` - Session type for OAuth logins. Default: :remember_me (D-43). The default value is `:remember_me`.

  * `:link_confirmation` - Account linking behavior when OAuth email matches existing account. Default: :required (D-01). The default value is `:required`.

  * `:trust_provider_email` (`t:boolean/0`) - Whether to auto-confirm email based on provider verification. Set false for Facebook (D-42). The default value is `true`.

* `:api_token` (`t:keyword/0`) - API token options. The default value is `[]`.

  * `:prefix` - Token prefix. Nil derives from otp_app: {otp_app}_sk_. Must match ^[a-z0-9_]+$ and not start with eyJ. The default value is `nil`.

  * `:custom_scopes` (list of `t:String.t/0`) - Custom scope strings in resource:action format. The default value is `[]`.

  * `:write_implies_read` (`t:boolean/0`) - Whether write scope implies read. Default: false. The default value is `false`.

  * `:require_expiry` (`t:boolean/0`) - Whether expiration is required. Default: false. The default value is `false`.

  * `:max_ttl` - Maximum TTL in seconds. Nil = no limit. The default value is `nil`.

  * `:cleanup_retention` (`t:pos_integer/0`) - Retention period for revoked/expired tokens in seconds. Default: 90 days. The default value is `7776000`.

  * `:activity_update_threshold` (`t:pos_integer/0`) - Minimum seconds between last_used_at writes. Default: 300. The default value is `300`.

  * `:default_page_size` (`t:pos_integer/0`) - Default page size for token listing. Default: 50. The default value is `50`.

  * `:max_page_size` (`t:pos_integer/0`) - Maximum page size. Default: 200. The default value is `200`.

  * `:api_token_schema` - The generated UserAPIToken schema module. The default value is `nil`.

* `:jwt` (`t:keyword/0`) - JWT options (requires Joken ~> 2.6 as optional dependency). The default value is `[]`.

  * `:enabled` (`t:boolean/0`) - Enable JWT support. Default: false. The default value is `false`.

  * `:algorithm` - Signing algorithm. Default: HS256. The default value is `"HS256"`.

  * `:issuer` - JWT issuer claim. Nil = otp_app name. The default value is `nil`.

  * `:access_ttl` (`t:pos_integer/0`) - Access token TTL in seconds. Default: 900 (15 min). The default value is `900`.

  * `:refresh_ttl` (`t:pos_integer/0`) - Refresh token TTL in seconds. Default: 30 days. The default value is `2592000`.

  * `:refresh` (`t:boolean/0`) - Enable refresh tokens. Default: true. The default value is `true`.

  * `:claims_builder` - Module implementing Sigra.JWT.ClaimsBuilder behaviour. The default value is `nil`.

  * `:verify_epoch` (`t:boolean/0`) - Verify user token_epoch on every JWT request. Default: true. The default value is `true`.

  * `:private_key` - PEM private key for RS256/ES256. The default value is `nil`.

* `:deletion` (`t:keyword/0`) - Account deletion options. The default value is `[]`.

  * `:strategy` - Deletion strategy. :soft_delete preserves row with deleted_at, :hard_delete removes row, :anonymize strips PII. Default: :soft_delete. The default value is `:soft_delete`.

  * `:grace_period_days` - Days before scheduled deletion executes. 0 or nil for immediate. Default: 14. The default value is `14`.

  * `:cooldown_hours` (`t:pos_integer/0`) - Hours after cancelling deletion before re-requesting is allowed. Default: 24. The default value is `24`.

  * `:notify` (`t:boolean/0`) - Send email notifications for deletion events. Default: true. The default value is `true`.

* `:hooks` (`t:keyword/0`) - Lifecycle hook callbacks. Each is a {module, function} tuple or nil. The default value is `[]`.

  * `:on_register` - Called after user registration. Receives (multi, context_map). Default: nil. The default value is `nil`.

  * `:on_email_change` - Called after email change confirmation. Receives (multi, context_map). Default: nil. The default value is `nil`.

  * `:on_password_change` - Called after password change. Receives (multi, context_map). Default: nil. The default value is `nil`.

  * `:on_delete` - Called when deletion is scheduled. Receives (multi, context_map). Default: nil. The default value is `nil`.

* `:audit` (`t:keyword/0`) - Structured audit logging options (Phase 9). See `Sigra.Audit`. The default value is `[]`.

  * `:audit_schema` - The generated AuditEvent schema module. Default: nil. The default value is `nil`.

  * `:retention_days` - Days to retain audit events. nil = keep forever (D-09). Default: nil. The default value is `nil`.

  * `:max_metadata_bytes` (`t:pos_integer/0`) - Cap on JSON-encoded metadata byte size (D-20). Default: 8192. The default value is `8192`.

  * `:reserved_prefixes` (list of `t:String.t/0`) - Reserved action prefixes developers cannot use (D-17, D-18). The default value is `["auth.", "session.", "mfa.", "oauth.", "api.", "account.", "sigra.", "passkey."]`.

# `t`

```elixir
@type t() :: %Sigra.Config{
  api_token: keyword(),
  audit: keyword(),
  confirmation: keyword(),
  cookie_domain: String.t() | nil,
  deletion: keyword(),
  email: keyword(),
  email_module: module() | nil,
  geo_ip: keyword(),
  hooks: keyword(),
  jwt: keyword(),
  lockout: keyword(),
  magic_link: keyword(),
  mailer: module() | nil,
  mfa: keyword(),
  oauth: keyword(),
  organizations_module: module() | nil,
  otp_app: atom() | nil,
  passkeys: keyword(),
  password: keyword(),
  password_policy: keyword(),
  rate_limiting: keyword(),
  repo: module(),
  require_confirmation: boolean(),
  reset: keyword(),
  scope_module: module() | nil,
  secret_key_base: String.t() | nil,
  session: keyword(),
  session_ttl: pos_integer(),
  suspicious_login: keyword(),
  token_ttl: keyword(),
  user_schema: module()
}
```

# `new!`
*since 0.1.0* 

```elixir
@spec new!(keyword()) :: t()
```

Creates a new `%Sigra.Config{}` struct from the given options.

Validates all options via `NimbleOptions` and raises
`NimbleOptions.ValidationError` for invalid or missing required options.
Only `:repo` and `:user_schema` are required; all other options have
secure defaults.

## Examples

    iex> config = Sigra.Config.new!(repo: Fake.Repo, user_schema: Fake.User)
    iex> config.repo
    Fake.Repo

    iex> config = Sigra.Config.new!(repo: Fake.Repo, user_schema: Fake.User)
    iex> config.cookie_domain
    nil

    iex> config = Sigra.Config.new!(repo: Fake.Repo, user_schema: Fake.User, cookie_domain: ".example.com")
    iex> config.cookie_domain
    ".example.com"

    iex> config = Sigra.Config.new!(repo: Fake.Repo, user_schema: Fake.User, cookie_domain: nil)
    iex> config.cookie_domain
    nil

    iex> config = Sigra.Config.new!(repo: Fake.Repo, user_schema: Fake.User, require_confirmation: true)
    iex> config.require_confirmation
    true

    iex> config = Sigra.Config.new!(repo: Fake.Repo, user_schema: Fake.User, session_ttl: 86_400)
    iex> config.session_ttl
    86_400

# `oauth_enabled?`
*since 0.1.0* 

```elixir
@spec oauth_enabled?(t()) :: boolean()
```

Returns whether OAuth is enabled AND has at least one configured provider.

Returns `true` only when `oauth[:enabled]` is not explicitly `false`
AND `oauth[:providers]` contains at least one entry. This prevents
callers from rendering an empty "Sign in with..." row on the default
config (which has no providers configured).

## Examples

    iex> config = Sigra.Config.new!(
    ...>   repo: Fake.Repo,
    ...>   user_schema: Fake.User,
    ...>   oauth: [enabled: true, providers: [google: [client_id: "x"]]]
    ...> )
    iex> Sigra.Config.oauth_enabled?(config)
    true

    iex> config = Sigra.Config.new!(repo: Fake.Repo, user_schema: Fake.User)
    iex> Sigra.Config.oauth_enabled?(config)
    false

    iex> config = Sigra.Config.new!(
    ...>   repo: Fake.Repo,
    ...>   user_schema: Fake.User,
    ...>   oauth: [enabled: false, providers: [google: [client_id: "x"]]]
    ...> )
    iex> Sigra.Config.oauth_enabled?(config)
    false

# `oauth_providers`
*since 0.1.0* 

```elixir
@spec oauth_providers(t()) :: keyword()
```

Returns the list of configured OAuth providers from the given config.

## Examples

    iex> config = Sigra.Config.new!(repo: Fake.Repo, user_schema: Fake.User, oauth: [providers: [google: [client_id: "x"]]])
    iex> Sigra.Config.oauth_providers(config)
    [google: [client_id: "x"]]

    iex> config = Sigra.Config.new!(repo: Fake.Repo, user_schema: Fake.User)
    iex> Sigra.Config.oauth_providers(config)
    []

---

*Consult [api-reference.md](api-reference.md) for complete listing*
