Password policy
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.
Status: v0.1.0 — Draft. Promoted from the GOV.UK parity scan (metadocsstack #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 upperlowerdigit/
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 (notonly revealed on error), associated via
aria-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).
- Sessiontoken lifetime (`specsauth/oauth-flow.kmd`).
- Machine-user / service-account credentials (non-password).