# Password hashing

Hash and verify passwords with Argon2id and rehash when parameters change.

`password` hashes, verifies, and flags rehashing with Argon2id; it issues no tokens and stores nothing.

## Quick start

```sh
PASSWORD_ADAPTER=argon2id
PASSWORD_TIME=3
PASSWORD_MEMORY=65536
PASSWORD_THREADS=4
```

```sh
PASSWORD_ADAPTER=argon2id
```

Defaults: `time` 3 (1 to 10), `memory` 65536 KiB (64 MiB; 8 MiB to 1 GiB), `threads` 4 (1 to 16), `salt_length` 16 (8 to 64), `key_length` 32 (16 to 128); out-of-range values fail `Open`. Plaintext over 1024 bytes returns `ErrPasswordTooLong`. See the [password reference](https://zenta-dev.github.io/zever/reference/config/#password).

## Hash at register, verify at login

```go title="login.go"
pw, err := c.Password()
if err != nil {
    return err
}
hash, err := pw.Hash(ctx, "correct horse battery staple")
if err != nil {
    return err
}
ok, err := pw.Verify(ctx, hash, "correct horse battery staple")
if err != nil {
    return err
}
rehash, err := pw.NeedsRehash(ctx, hash)
```

```text
hash:   $argon2id$v=19$m=65536,t=3,p=4$<salt>$<key>
ok:     true
rehash: false (true after a cost-parameter bump)
```

Stored form is PHC; salts come from `crypto/rand`, comparison is constant-time. `Verify` returns `true, nil` (match), `false, nil` (mismatch, reject generically), or `_, ErrInvalidHash` (corrupt, force reset); check the sentinel with `errors.Is`.

## Retune costs without a forced reset

1. Benchmark on production-class hardware; a laptop number can be too cheap.
2. Deploy; old hashes keep verifying.
3. `NeedsRehash` flags stale hashes per login; rehash and persist.
4. Track the stale count to zero.

## Production checklist

- Hashing cost does not limit attempts; rate-limit login ([Rate limiting](https://zenta-dev.github.io/zever/guides/security/ratelimit/)).
- Never log passwords or hashes; errors name the failure, not the value.

## Troubleshooting

<details>
<summary>`ErrInvalidHash` on a known account</summary>

Stored value truncated or corrupted. Confirm with `errors.Is`, force a reset.
</details>

<details>
<summary>Logins slow to a crawl</summary>

Cost parameters exceed fleet capacity. Benchmark, lower toward defaults, scale out first.
</details>

<details>
<summary>`NeedsRehash` is true for every user</summary>

Parameters changed since minting. Rehash on each account's next successful login.
</details>

<details>
<summary>Password rejected for length</summary>

Plaintext exceeds 1024 bytes. Reject at the boundary before hashing.
</details>

## Related

[Authentication](https://zenta-dev.github.io/zever/guides/security/auth/) · [Rate limiting](https://zenta-dev.github.io/zever/guides/security/ratelimit/)
