1# user-auth Specification23## Purpose4Covers how people sign in to Tally, how long their sessions last, and how the system protects accounts from password guessing.5## Requirements6### Requirement: Password login7The system SHALL authenticate users with an email address and password, storing only argon2id password hashes.89#### Scenario: Valid credentials10- **WHEN** a user submits a registered email and the correct password11- **THEN** the system creates a session and sets an `HttpOnly`, `Secure` session cookie12- **AND** redirects the user to their last visited project1314#### Scenario: Invalid credentials15- **WHEN** a user submits an unknown email or a wrong password16- **THEN** the system responds with the generic message "Invalid email or password"17- **AND** does not reveal which field was wrong1819### Requirement: Session expiry20Sessions SHALL expire after 30 days without activity, after which the user MUST log in again.2122#### Scenario: Expired session23- **WHEN** a request arrives with a session cookie last used more than 30 days ago24- **THEN** the system deletes the session and redirects to the login page2526#### Scenario: Activity extends session27- **WHEN** a request arrives with a session last used 29 days ago28- **THEN** the request succeeds and the session's last-used time is updated2930### Requirement: Remember me31The login form SHALL offer a "Remember me" option that extends the session inactivity timeout to 90 days.3233#### Scenario: Remember me selected34- **WHEN** a user logs in with "Remember me" checked35- **THEN** the session inactivity timeout is 90 days instead of 303637### Requirement: Account lockout38The system MUST lock an account for 15 minutes after 5 consecutive failed login attempts.3940#### Scenario: Fifth failed attempt41- **WHEN** a user fails to log in 5 times in a row42- **THEN** further login attempts for that account are rejected for 15 minutes43- **AND** the response is indistinguishable from an invalid-credentials response4445#### Scenario: Successful login resets counter46- **WHEN** a user fails to log in 3 times and then logs in successfully47- **THEN** the failed-attempt counter resets to zero48