Skip to content

fix(auth): drop special-char password rule + honest set/reset errors (HUGO-147)#17

Merged
jaraf3330 merged 1 commit into
mainfrom
fix/hugo-147-password-policy
Jun 18, 2026
Merged

fix(auth): drop special-char password rule + honest set/reset errors (HUGO-147)#17
jaraf3330 merged 1 commit into
mainfrom
fix/hugo-147-password-policy

Conversation

@jaraf3330

Copy link
Copy Markdown
Contributor

Why

HUGO-147: a strong alphanumeric-only password (zMN8iBS9Lkzib5J) was rejected because the policy required a special character, while Qwerta123! passed. On top of that, every set/reset failure — including a password-policy violation — showed the misleading "Something went wrong. The link may have expired." Users couldn't tell why they were blocked or how to fix it.

Decision (2026-06-18)

  • Length is the primary strength criterion. Min 8 chars is the only enforced rule; character classes (upper/lower/number/special) are encouraged, not required.
  • Users must see requirements live when setting/resetting a password, and always get an honest, specific reason for a failure.

Changes

API

  • password.service.ts — policy is length-only; alphanumeric passwords accepted. PASSWORD_POLICY_VIOLATION hint reworded.
  • error-response.ts — small allowlist of non-sensitive error codes exposed in production (PASSWORD_POLICY_VIOLATION, MISSING_PASSWORD, token codes) so the UI can map them; everything else stays fully generic. Login (AUTHENTICATION_FAILED) and the reset-request flow remain generic → no email-enumeration leak.
  • password.service.test.ts — updated, incl. regression that zMN8iBS9Lkzib5J passes.

Auth

  • PasswordRequirements.tsx (new) + password-policy.ts (new) — live requirements checklist mirroring the API policy.
  • SetPasswordForm.tsxfailure() maps the API error code to a specific localized message (tooShort / linkInvalid / generic) instead of the link-expired catch-all; client-side policy check before submit.
  • api.tsApiFailure.code + extractCode().
  • i18n en.ts / es.ts — new keys; misleading message reworded.

Docs

  • brief.md — Password Rules updated + new "Password UX & Error Transparency" section.

Verification

  • API unit tests: 361 passed, 0 assertion failures (37 failures are the pre-existing missing @unlikeotherai/qr-art 2FA dep, unrelated to this change).
  • Auth typecheck + ESLint clean.
  • Two-round code review (Claude reviewer → Codex fix → adversarial re-review): final verdict SHIP; all 8 allowlisted codes verified safe against account enumeration.

Resolves HUGO-147.

🤖 Generated with Claude Code

…(HUGO-147)

Why: a strong alphanumeric-only password (e.g. zMN8iBS9Lkzib5J) was rejected
because the policy required a special character, and every set/reset failure —
including a password-policy violation — surfaced the misleading "Something went
wrong. The link may have expired." This left users unable to tell why they
couldn't proceed or how to fix it.

Decision (2026-06-18): length is the primary strength criterion; min 8 chars is
the only enforced rule. Character classes are encouraged, not required. Users
must see requirements live and always get an honest reason for a failure.

- API: password policy is length-only (password.service.ts); PASSWORD_POLICY
  hint reworded; unit tests updated incl. regression on alphanumeric password.
- API: expose a small allowlist of non-sensitive error codes in production
  (password-policy / token codes) so the UI can map them; everything else stays
  generic. Login + reset-request remain fully generic (no enumeration leak).
- Auth: live PasswordRequirements checklist on set/reset; client-side policy
  mirror (password-policy.ts); failure() maps codes to specific localized
  messages (tooShort / linkInvalid / generic) instead of the link-expired
  catch-all. en/es translations added.
- Docs: brief Password Rules updated + new Password UX & Error Transparency.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@jaraf3330 jaraf3330 merged commit d041b78 into main Jun 18, 2026
1 check failed
@jaraf3330 jaraf3330 deleted the fix/hugo-147-password-policy branch June 18, 2026 19:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant