Document the self-service password change

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KGcjxF1cNLcuwc3DAPcnfj
This commit is contained in:
2026-09-29 15:31:21 +05:30
parent 6068b2c3c7
commit e0bd764e44
2 changed files with 70 additions and 0 deletions

View File

@@ -2470,6 +2470,47 @@ carrying no host or username, another merchant's shop and camera both 404,
malformed identifiers 404 rather than 500, one real sale (INR 1000, V-1) read
back by id, and every tenant route still 200 for an ordinary tenant account.
## Nobody could change their own password
`POST /api/auth/password`. The cost of its absence was measured rather than
argued. Rotating the three production accounts took a shell on the host, three
round trips, and briefly left the **platform admin** — the account that reads
every company on the estate — with the password `PASTE_IT_HERE`, because a
placeholder in a pasted command was taken literally and there was no way to
correct it from the product itself.
A manager could always reset somebody *else's* password. A platform admin could
be reset by nobody: they have no client, so the team routes are not theirs, and
`provision user` on the host was the only route. For software that puts
accounts on shop-floor PCs and staff phones, this is not a feature — it is what
makes every other credential decision recoverable.
- **`authed`, not `tenantOnly`.** A session is not a company's data, and the
account with no company is precisely the one that had no route. Scoping it by
client would have reproduced the hole it exists to close — which is also why
`SetUserPassword` is not client-scoped the way `ResetMemberPassword` beside
it is. The user id comes from the verified session, never the request.
- **The current password is required**, or an access token alone takes an
account over permanently instead of for the rest of the day.
- **Every other session is revoked and the caller's is kept.** A failure there
is logged, not returned: the password is already changed, and an error would
send the user to retry with a current password that no longer exists.
Verified live against production: wrong current password 403 and nothing
changed, a change revoking **45** stale sessions while the caller's own
survived, the new password in and the old one out, then changed back.
### And a shell quoting trap worth not repeating
The first attempt to rotate the admin password from the operator's terminal
ran with the literal string `PASTE_IT_HERE`. The second, reading the value out
of a file, produced **no output at all** and changed nothing — `~` was not
expanded in that eval context, `awk` could not open the file, returned
non-zero, and `&&` short-circuited silently. Absolute paths and `;` instead of
`&&` fixed it, and echoing the password *length* first is what proved the
third attempt was about to set something real. A command handed to somebody to
paste should contain nothing to edit and should fail loudly.
## Setting up on a new machine
1. Copy the `Behavision` folder **including `.env`** (gitignored, holds