Skip to content

Latest commit

 

History

History
29 lines (21 loc) · 2.2 KB

File metadata and controls

29 lines (21 loc) · 2.2 KB

Changelog

0.2.0 — 2026-06-10

Security hardening.

  • Login now returns the same generic HTTP 401 for both invalid credentials and disabled accounts, removing an account-status enumeration oracle (CWE-204).
  • Added an optional rate_limiter hook on init_users / attach_routes, awaited on the login and password-reset-request endpoints to enable brute-force / email-bombing protection (CWE-307).
  • Verification / reset email helpers raise a clear error if the URL template still points at the placeholder example.com domain.

0.1.0 — 2026-05-16

Initial release.

  • SQLAlchemyBaseUserTable declarative mixin — UUID4 id, normalized email, argon2id hash, is_active/is_verified/is_superuser, password_version.
  • UserManagercreate / get_by_email / authenticate / request_verify / verify / request_password_reset / reset_password / update / delete.
  • UserTokensemail_verify + password_reset JWTs with type binding + password_version invalidation.
  • Default Jinja2 templates for verification + reset emails (HTML + plain text).
  • HTTP routes under /usersregister, login, verify/request, verify/{token}, password-reset/request, password-reset/{token}.
  • Account enumeration prevention — /verify/request and /password-reset/request always 202.
  • Timing-equalized authentication — argon2id runs against a dummy hash on unknown emails.
  • Reset bumps password_version to invalidate every outstanding token in one DB write.
  • Minimum 32-character token signing secret enforced at construction time.
  • init_users(app, manager=...) + Depends(get_user_manager) + WeakKeyDictionary registry.

Security review applied before ship:

  • Fixed double-decode bug (CWE-287) — verify() and reset_password() now use peek_*_token_sub() to extract the user_id before the DB lookup, then run the full pv check against the loaded user. Without this fix, any user whose password_version had ever been bumped (anyone who completed a password reset) would be unable to verify or reset again.
  • Documented three known accepted risks in README: 409-on-register enumeration, 403-on-inactive credential confirmation, absence of built-in rate limiting / session issuing.