Password policy
identity specs/identity/password-policy.kmd
The NCSC/NIST-aligned password rules for Koder ID — the ONLY surface in the Stack that accepts a user password, since Koder ID is the sole identity provider (auth/oauth-flow.kmd R1). Modern guidance: length over complexity, no forced expiry, no composition rules, no security questions, breached-password screening, and password-manager-friendly input. Applies to account creation, password change, and reset.
When this pattern applies
Primary triggers
- Implement or change Koder ID password rules
All triggers
- Design the password field for Koder ID sign-up / reset
- Decide minimum length, expiry, or complexity rules for a password
- Add a strength meter or show/hide toggle to a credential form
Specification body
Spec — Password policy
Status: v0.1.0 — Draft. Promoted from the GOV.UK parity scan (meta/docs/stack #096); aligns with NCSC password guidance + NIST SP 800-63B. Scope is Koder ID only — no other Koder component has a password field (
specs/auth/oauth-flow.kmdR1: Koder ID is the sole identity provider; products receive tokens, never credentials). Sources: https://www.ncsc.gov.uk/collection/passwords · https://pages.nist.gov/800-63-3/sp800-63b.html
R1 — Length, not composition
- Minimum 8 characters. (12+ encouraged via the strength meter, R6, but never hard-required beyond 8.)
- No upper length cap below 64; accept passphrases up to at least 256 characters. Never silently truncate.
- No composition rules — do NOT require a mix of upper/lower/digit/ symbol. Any printable Unicode character (including spaces and emoji) is allowed.
R2 — No forced expiry
- Passwords do not expire on a schedule. Do not prompt periodic changes.
- Force a reset only on evidence of compromise (breach screening R3, detected credential stuffing, or user request).
R3 — Breached-password screening
- On set/change, screen the candidate against a known-compromised password corpus using a k-anonymity range query (only a hash prefix leaves the server; the full password/hash is never sent externally).
- A match is rejected with a clear, non-shaming message
(
specs/errors/user-facing-messages.kmd): "This password has appeared in a data breach. Choose a different one." - Screening is the ONLY content denylist; do not also ban dictionary words or enforce arbitrary blocklists.
R4 — No knowledge-based recovery
- No security questions and no password hints — both are weaker than the password and are prohibited.
- Account recovery goes through verified email/second-factor flows (separate spec), never "mother's maiden name".
R5 — Input UX (password-manager friendly)
- Allow paste into the password field (do not block it).
- Provide a show/hide toggle (eye icon) that reveals the entered
value; default hidden; the toggle is a real
<button>with an accessible label that reflects state ("Show password"/"Hide password"). - Use
autocomplete="new-password"on create/change andautocomplete="current-password"on sign-in so managers work. - Never disable autofill.
R6 — Strength feedback, not gatekeeping
- Show a strength meter (entropy/zxcvbn-style estimate) that guides toward longer/passphrase choices.
- The meter is advisory: anything meeting R1 (≥8, not breached) is accepted. The meter never blocks submission on its own.
R7 — Storage & rate limiting (contract, not implementation)
- Store only a salted, memory-hard hash (argon2id or equivalent), per-user salt; never plaintext or reversible encryption.
- Defend online guessing with throttling (progressive delay) in preference to hard lockout (which enables denial-of-service); lockout, if used, is time-boxed and self-clearing.
- Authentication telemetry follows
policies/identity-data-retention.kmd(no plaintext credentials in logs, ever).
R8 — Accessibility & i18n
- The field has a real
<label>; requirements are stated up front (not only revealed on error), associated viaaria-describedby. - Errors (too short, breached) are specific and actionable
(
specs/errors/user-facing-messages.kmd), announced to assistive tech. - All strings (label, hint, strength levels, errors, toggle) are
translatable per
specs/i18n/contract.kmd; length is counted in Unicode code points, locale-independent.
Não-escopo
- 2FA / passkey / WebAuthn enrolment (separate auth specs).
- The account-recovery flow itself (email verification, second factor).
- Session/token lifetime (
specs/auth/oauth-flow.kmd). - Machine-user / service-account credentials (non-password).
References
specs/auth/oauth-flow.kmdspecs/identity/login-resolution.kmdspecs/errors/user-facing-messages.kmdpolicies/identity-data-retention.kmdspecs/i18n/contract.kmd