Password reset
User flow
Section titled “User flow”- Login page, “Forgot password?”.
- Enter email and submit.
- z4j always responds “check your email” regardless of whether the email exists (prevents enumeration).
- If the email exists, a one-shot reset link is sent. The reset token TTL is 30 minutes.
- User clicks the link, fills in a new password, which must satisfy the password policy.
- On save, all existing sessions for that user are invalidated.
Email delivery
Section titled “Email delivery”Password reset emails go through the project’s email notification channel (the same channel used for invitations). Without an active email channel on at least one of the user’s projects, the reset link cannot be sent and the user must reset via the CLI path below.
Rate limits
Section titled “Rate limits”Both POST /auth/password-reset/request and POST /auth/password-reset/confirm share a single per-IP bucket: 10 hits per minute combined. Tighter than the login cap because a legitimate user only needs one or two hits (one to request, one to confirm); higher rates indicate enumeration or token brute-force attempts.
Admin reset via CLI
Section titled “Admin reset via CLI”For lost admin accounts or stretches without email delivery, change the password directly from the brain container:
# Prompt for the password on stdin (recommended; never echoed):z4j changepassword owner@example.com --password-stdinOr pass it inline (not recommended, ends up in shell history):
z4j changepassword owner@example.com --password 'new-password'Requires direct brain-container access.
Last-resort recovery
Section titled “Last-resort recovery”If you have lost all admins AND CLI access:
- Connect to Postgres directly.
- Generate an argon2id hash with an external tool (
argon2-cli, theargon2-cffiPython package, etc.). UPDATE users SET password_hash = '$argon2id$...' WHERE email = 'owner@example.com';- Log in with the new password.
This is a break-glass procedure. Log the event externally and treat it as a compromise drill.
- Reset requested writes an audit entry with the email and IP (not the token).
- Reset completed writes an audit entry with the
user_id. - CLI
changepasswordwrites an audit entry attributed to the operator.