# `Sigra.MFA.Trust`
[🔗](https://github.com/sztheory/sigra/blob/v1.20.0/lib/sigra/mfa/trust.ex#L1)

Trust cookie HMAC signing, verification, and mass revocation.

"Trust this browser" allows users to skip MFA on recognized browsers.
The trust cookie is an HMAC-signed payload containing the user_id,
trust_epoch, and issued timestamp. Verification checks the HMAC
signature, user_id match, epoch match, and TTL.

## Security Properties

- HMAC-signed via `Plug.Crypto.sign/4` using the app's `secret_key_base` (D-46)
- Cookie payload: `{user_id, trust_epoch, issued_at}` (D-52)
- Mass revocation via `mfa_trust_epoch` increment on user record (D-48)
- HttpOnly, Secure, SameSite=Lax cookie options (D-54)
- Verified against current user_id to prevent cross-user cookie reuse (Pitfall 6)

# `cookie_name`
*since 0.6.0* 

```elixir
@spec cookie_name() :: String.t()
```

Returns the trust cookie name.

# `cookie_opts`
*since 0.6.0* 

> This function is deprecated. Use cookie_opts/1 with a %Sigra.Config{} so cookie_domain is honored..

```elixir
@spec cookie_opts() :: no_return()
```

Removed: use `cookie_opts/1` with a `%Sigra.Config{}` so `:cookie_domain`
is honored.

Previously this arity-0 form returned domain-unaware cookie options as a
backwards-compatibility shim. It was removed because silently dropping
`:cookie_domain` reopens the subdomain-auth bug Phase 10 fixed: any
caller still using this form would write cookies without the configured
domain and break subdomain sign-in without a single compile error.

Call `cookie_opts/1` with your `%Sigra.Config{}` instead.

# `cookie_opts`
*since 0.10.0* 

```elixir
@spec cookie_opts(Sigra.Config.t()) :: keyword()
```

Returns remember-me cookie options honoring `:cookie_domain` from the given config.

When `config.cookie_domain` is `nil`, returns the base host-only options.
When it is a binary (e.g., `".example.com"`), appends `domain: <value>`.

# `revoke_all`
*since 0.6.0* 

```elixir
@spec revoke_all(module(), module(), term()) :: {non_neg_integer(), nil}
```

Revokes all trusted browsers for a user by incrementing `mfa_trust_epoch`.

Uses `update_all` for atomic increment. All existing trust cookies
become invalid because their epoch no longer matches.

## Parameters

- `repo` - The Ecto repo module
- `user_schema` - The generated user Ecto schema module
- `user_id` - The user's ID

# `sign`
*since 0.6.0* 

```elixir
@spec sign(String.t(), term(), non_neg_integer(), pos_integer()) :: binary()
```

Signs a trust cookie for the given user and epoch.

Returns a binary cookie value signed with HMAC via `Plug.Crypto.sign/4`.

## Parameters

- `secret_key_base` - The host app's secret key base
- `user_id` - The authenticated user's ID
- `trust_epoch` - The user's current `mfa_trust_epoch` value
- `trust_ttl` - Trust cookie TTL in seconds

# `verify`
*since 0.6.0* 

```elixir
@spec verify(String.t(), binary(), term(), non_neg_integer(), pos_integer()) ::
  {:ok, term()} | {:error, :invalid}
```

Verifies a trust cookie against the current user and epoch.

Returns `{:ok, user_id}` if valid, `{:error, :invalid}` otherwise.
Checks: HMAC signature, TTL, user_id match, and trust_epoch match.

## Parameters

- `secret_key_base` - The host app's secret key base
- `cookie` - The trust cookie value to verify
- `current_user_id` - The currently authenticated user's ID
- `current_trust_epoch` - The user's current `mfa_trust_epoch` value
- `trust_ttl` - Trust cookie TTL in seconds

---

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