# `Sigra.Account.PasswordChange`
[🔗](https://github.com/sztheory/sigra/blob/v1.20.0/lib/sigra/account/password_change.ex#L1)

Password change lifecycle: change, set for OAuth users, force change.

Handles password changes with current password verification, session
invalidation, and lifecycle hooks. Also supports OAuth-only users
setting an initial password (without current password check).

## Security Properties

- Current password verification before change (D-35)
- Session invalidation configurable (D-34, D-42)
- Password change notification (D-37, D-42)
- Force password change flag for admin use (D-38)
- Telemetry spans for all operations (D-43)

# `change`
*since 0.8.0* 

```elixir
@spec change(module(), map(), String.t(), map(), keyword()) ::
  {:ok, map()} | {:error, :invalid_password | Ecto.Changeset.t()}
```

Change password with current password verification.

Validates the current password, then updates the password hash,
sets `password_changed_at`, clears `must_change_password`, and
invalidates other sessions (configurable).

## Options

- `:changeset_fn` - `(user, attrs -> Ecto.Changeset.t())` for password update
- `:validate_password_fn` - `(user, password -> boolean())` to verify current password
- `:session_store` - SessionStore for session invalidation
- `:config` - Optional config for hooks and password settings
- `:except_token` - Current session token to preserve

## Returns

- `{:ok, user}` on success
- `{:error, :invalid_password}` if current password is wrong
- `{:error, changeset}` on validation failure

# `clear_force_change`
*since 0.8.0* 

```elixir
@spec clear_force_change(module(), map()) ::
  {:ok, map()} | {:error, Ecto.Changeset.t()}
```

Clear the force password change flag.

Called after the user successfully changes their password.

# `force_change_required?`
*since 0.8.0* 

```elixir
@spec force_change_required?(map()) :: boolean()
```

Check if a user must change their password.

Returns `true` if the `must_change_password` flag is set on the user.
Used by `Sigra.Plug.RequirePasswordChange` to redirect users.

# `require_force_change`
*since 0.8.0* 

```elixir
@spec require_force_change(module(), map()) ::
  {:ok, map()} | {:error, Ecto.Changeset.t()}
```

Admin API: require user to change password on next login.

Sets the `must_change_password` flag to `true`. The user will be
redirected to the password change form until they comply.

# `set_for_oauth_user`
*since 0.8.0* 

```elixir
@spec set_for_oauth_user(module(), map(), map(), keyword()) ::
  {:ok, map()} | {:error, Ecto.Changeset.t()}
```

Set password for OAuth-only user (no current password verification).

Used when an OAuth-only user wants to add a password to enable
hybrid authentication. Requires sudo mode upstream.

## Options

- `:changeset_fn` - `(user, attrs -> Ecto.Changeset.t())` for password set
- `:session_store` - Optional SessionStore
- `:config` - Optional config for hooks

## Returns

- `{:ok, user}` on success
- `{:error, changeset}` on validation failure

---

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