# `AshAuthentication.HashProvider`
[🔗](https://github.com/team-alembic/ash_authentication/blob/main/lib/ash_authentication/hash_provider.ex#L5)

A behaviour providing password hashing.

# `deterministic?`

```elixir
@callback deterministic?() :: boolean()
```

Whether the same input always produces the same hash output.

Deterministic providers (e.g. SHA-256) allow atomic database-level
verification by hashing the input and matching directly against stored
values. Non-deterministic providers (e.g. bcrypt, argon2) use random salts,
so verification requires loading stored hashes and comparing individually.

# `hash`

```elixir
@callback hash(input :: String.t()) :: {:ok, hash :: String.t()} | :error
```

Given some user input as a string, convert it into it's hashed form.

# `hash`
*optional* 

```elixir
@callback hash(input :: String.t(), context :: map()) ::
  {:ok, hash :: String.t()} | :error
```

Hash with action context.

An optional variant of `hash/1` that receives the Ash context from the
current action (changeset or action input). This enables hash providers
that need external state — for example, a shared-salt provider can read
a pre-generated salt from the context.

When implemented, this callback is preferred over `hash/1` by the
recovery code strategy's hashing change and verify action.

# `minimum_entropy`

```elixir
@callback minimum_entropy() :: non_neg_integer()
```

The minimum bits of input entropy required for this hash provider to be safe.

Slow hash providers like bcrypt and argon2 return `0` because their
computational cost makes brute-force attacks impractical regardless of input
entropy. Fast deterministic hash providers like SHA-256 require high-entropy
inputs (e.g. 60+ bits) because their speed makes low-entropy inputs
vulnerable to offline brute-force attacks.

# `simulate`

```elixir
@callback simulate() :: false
```

Attempt to defeat timing attacks by simulating a password hash check.

See [Bcrypt.no_user_verify/1](https://hexdocs.pm/bcrypt_elixir/Bcrypt.html#no_user_verify/1) for more information.

# `valid?`

```elixir
@callback valid?(input :: String.t(), hash :: String.t()) :: boolean()
```

Check if the user input matches the hash.

# `call_hash`

```elixir
@spec call_hash(module(), String.t(), map()) :: {:ok, String.t()} | :error
```

Calls `hash/2` if the provider implements it, otherwise falls back to `hash/1`.

---

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