obsidian-vault/Infra-Network/AUTH-USERS-SPEC.md
Roger 06acaff8a8 docs: RentCharge 007.2026 money privacy + profile status
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 18:19:56 +00:00

4.3 KiB
Raw Blame History

SPEC — Users, Access Matrix, registration, sessions and security

Date: 2026-09-19
Status: hardened Users + Access Matrix; SMTP configurado e validado (2026-09-19).
Module: backend/app/modules/users · Admin UI /users · /users/access

Design references (not a framework swap)

Patterns adapted from production FastAPI auth libraries (kept in-house RBAC matrix):

  • fastapi-fullauth — lockout, hashed reset tokens, email verification/reset, RBAC permissions, anti-enumeration
  • AuthWarden — single-use reset tokens, OTP attempt limits, brute-force lockout
  • OWASP Authentication / Session / Password-reset cheat sheets

RentCharge keeps its own SQLite models, cookie sessions and permissions-first Access Matrix (module.view.action).

Functional scope (both sides)

A — Self-service (/login, /signup, /reset-password, /account)

  1. Public registration with strong password + email OTP verification.
  2. Forgot-password → single-use email token (SHA-256 stored, 1 hour).
  3. Account profile, email verification, password change with strength meter.
  4. Forced password change when must_change_password is set.

B — Admin Users + Access Matrix (/users, /users/access)

  1. Create staff logins with generated strong passwords (not shared starter defaults).
  2. Edit login (username, nickname, display name, recovery email).
  3. Set password (modal + strength meter) or email a reset token.
  4. Require password change on first login / after admin reset.
  5. Role assignment + full Role × Permission matrix with dirty-state and default-drift highlight.
  6. Sessions revoke + security activity audit.

Security controls

  • Password rules are chosen by Admin under /users/password-policy (not hard-coded). Presets: PIN 6+ digits · alphanumeric · strong · complex · custom toggles (uppercase / lowercase / digit / special / min length / block nick-email / block common).
  • Passwords: bcrypt cost 12; validation always follows the saved admin policy.
  • Account lockout after 5 consecutive failed logins (15 minutes) + IP/identity rate limits.
  • Reset tokens: 256-bit random, stored as SHA-256 only, single-use, invalidate previous tokens.
  • Registration OTP: HMAC-SHA256, 10 min, max 5 attempts.
  • Sessions: JWT + server-side session id; HttpOnly Secure SameSite=Strict cookie; idle + absolute timeouts.
  • Logout / password change / reset / disable revoke sessions.
  • Generic public responses to reduce account enumeration.
  • Passwords and raw tokens never written to auth_events.

New / updated API

Method Path Purpose
GET /api/auth/password-policy Policy hint for UIs
POST /api/auth/password-strength Strength score helper
POST /api/users/{id}/send-password-reset Admin emails recovery token
GET /api/users/generate-password Cryptographically strong starter
PUT /api/users/{id} Now accepts username (edit login)
POST /api/users must_change_password, send_invite_email
POST /api/users/{id}/set-password must_change_password flag

Database (additive)

users columns:

  • must_change_password
  • failed_login_count
  • locked_until

Mail transport (VM500)

Validated 2026-09-19 — OTP verification and password-reset emails delivered.

Setting Value
Host mail.myvexx.com
Port 465 (SMTP SSL)
User admin@myvexx.com
From Rent & Charge <admin@myvexx.com>
Config /home/mini/rentcharge/config/rentcharge.env (symlink /etc/rentcharge.env)
Also Postfix on VM500 relays [mail.myvexx.com]:465 with SASL

App flags: SMTP_SSL=true, SMTP_STARTTLS=false. Credentials stay only in env (never in Git).

E2E checks: POST /api/auth/forgot-password → HTTP 200; inbox received Rent & Charge password reset and Your Rent & Charge verification code.

Verification checklist

  • Weak passwords rejected on register / change / admin set
  • Generate strong password fills create form
  • Edit login updates username + email
  • Email reset from Users works when SMTP configured
  • Forced change redirects to /account
  • Access matrix dirty badge + amber default-drift cells
  • Backend tests: python -m unittest backend.tests.test_auth_users