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

95 lines
4.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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](https://github.com/mdfarhankc/fastapi-fullauth) — lockout, hashed reset tokens, email verification/reset, RBAC permissions, anti-enumeration
- [AuthWarden](https://github.com/timihack/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
- [x] 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`