Enhancement Proposal

Proposal: Credential policy and breached-password protection

Argon2id (ADR-0015) hashes passwords, but there is no policy and no breached-password check. This specs both on the authentication-method (ADR-0015) and realm-policy (ADR-0012) seams — no new architecture.

Motivation

Weak and breached passwords are the bulk of account-takeover. NIST 800-63B guidance is clear: prefer length and breach-checking over complexity rules and forced rotation. None of it exists today.

Design

  • Per-realm credential policy (ADR-0012): minimum length, optional disallow-lists (common/dictionary), password history; expiry is off by default (NIST-discouraged).
  • Breached-password check via the HIBP k-anonymity range API (a hash prefix is sent, never the password) at set-time and optionally at login; a known-breached password is rejected on set and flagged on login.
  • Brute-force / credential-stuffing protection: throttling and backoff (proposal 0006), per-principal lockout windows, and breached-credential detection. Velocity limits and lockout counters are part of proposal 0006's layered rate-limit umbrella: this proposal owns the per-realm policy semantics (what counts as a lockout, its windows and thresholds), 0006 the enforcement layer.
  • Passkeys preferred (ADR-0020): policy can require or nudge passwordless.

Alternatives considered

  • Complexity-heavy policies — rejected (NIST 800-63B: length + breach-check beats composition rules, which drive weak, reused passwords).
  • A locally-hosted breach corpus — rejected (HIBP k-anonymity is privacy-preserving and maintained); offered as an air-gapped option.

Graduation criteria

A realm enforces minimum length and the breach check; a known-breached password is rejected at set; brute-force is throttled. Abuse-case tests (ADR-0028): a breached password is rejected; a credential-stuffing burst is throttled.

Backward compatibility

On the authentication-method (ADR-0015) and realm policy (ADR-0012); no architecture change.

Open questions

  • HIBP vs an air-gapped breach corpus; default policy values.