Merge pull request 'docs(backend): document the password-reset endpoints and table' (#8) from docs/password-reset into main
Reviewed-on: #8 Reviewed-by: Colby Whitlock <whitlocktech@gmail.com>
This commit is contained in:
@@ -142,6 +142,20 @@ Seeded keys: `site_mode` (default `maintenance`), `site_mode_changed_at`,
|
|||||||
| ip | VARCHAR(45) NULL | from `req.ip` (needs `trust proxy`) |
|
| ip | VARCHAR(45) NULL | from `req.ip` (needs `trust proxy`) |
|
||||||
| created_at | DATETIME DEFAULT CURRENT_TIMESTAMP | |
|
| created_at | DATETIME DEFAULT CURRENT_TIMESTAMP | |
|
||||||
|
|
||||||
|
### password_resets — self-service reset links
|
||||||
|
| col | type | notes |
|
||||||
|
|---|---|---|
|
||||||
|
| id | INT PK AUTO_INCREMENT | |
|
||||||
|
| token_hash | CHAR(64) UNIQUE NOT NULL | sha256 hex of the opaque token; **plaintext never stored** |
|
||||||
|
| user_id | INT NOT NULL FK→users(id) ON DELETE CASCADE | the account this reset targets |
|
||||||
|
| status | ENUM('pending','used') DEFAULT 'pending' | single-use (atomic `markUsed`) |
|
||||||
|
| requested_ip | VARCHAR(64) NULL | who asked (audit only) |
|
||||||
|
| expires_at | DATETIME NOT NULL | ~1h TTL, enforced in the model on top of this |
|
||||||
|
| created_at / used_at | DATETIME | |
|
||||||
|
|
||||||
|
Same "store only the hash of an opaque token" pattern as `user_invites` / `mobile_refresh_tokens`.
|
||||||
|
A DB read never yields a usable reset link. See §4 `/auth/password/*`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. API contract
|
## 4. API contract
|
||||||
@@ -154,10 +168,17 @@ accepts `Authorization: Bearer` for API testing).
|
|||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
| POST | `/login` | — (rate-limited) | `{username,password}` | verify, set cookie, log `auth.login`, update `last_login_at` |
|
| POST | `/login` | — (rate-limited) | `{username,password}` | verify, set cookie, log `auth.login`, update `last_login_at` |
|
||||||
| POST | `/logout` | cookie | — | clear cookie |
|
| POST | `/logout` | cookie | — | clear cookie |
|
||||||
| GET | `/me` | cookie | — | current user (no hash) or 401 — client bootstraps auth state |
|
| GET | `/me` | cookie / bearer | — | current user (no hash) or 401 — client bootstraps auth state |
|
||||||
|
| POST | `/password/forgot` | — (rate-limited) | `{email}` | email a single-use, ~1h reset link to **every active account** on the address; **always** returns the same generic 200 (no account enumeration). Email is non-unique, so several accounts may each get a link naming their username. Logs `account.password.reset.request`. |
|
||||||
|
| GET | `/password/reset/:token` | — | — | validate a link → `{username}` for the form, else 404 (never distinguishes expired/used/never-existed) |
|
||||||
|
| POST | `/password/reset/:token` | — (rate-limited) | `{password}` | consume the single-use link, rotate the hash, and revoke **all** sessions (web cutoff + mobile refresh tokens). Does **not** sign the user in — they log in fresh (so a 2FA account still passes TOTP). Logs `account.password.reset.complete`. |
|
||||||
|
|
||||||
No public `register`. First admin is bootstrapped by `seed.js` from env (see §6). Further
|
**Password reset.** Uses the same audited pattern as `user_invites`: an opaque 32-byte token
|
||||||
admins are created under `/admin/users`.
|
whose **sha256 hash only** is stored in `password_resets`, single-use and short-lived (~1h). It
|
||||||
|
also serves SSO-only accounts (null `password_hash`) as their "set an initial password" path. The
|
||||||
|
reset link points at the web front end (`/account/reset/:token`); the Android app hands off here
|
||||||
|
rather than shipping its own reset screen (docs/android/PLAN.md §4.2). First admin is bootstrapped
|
||||||
|
by `seed.js` from env (see §6); further staff are created under `/admin/users` or via email invites.
|
||||||
|
|
||||||
### /public (public.routes.js → public.controller.js) — all GET, no auth
|
### /public (public.routes.js → public.controller.js) — all GET, no auth
|
||||||
| Method | Path | Notes |
|
| Method | Path | Notes |
|
||||||
|
|||||||
Reference in New Issue
Block a user