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:
29
API.md
29
API.md
@@ -43,6 +43,7 @@ user; the tenant is always taken from the session and never from the request.
|
||||
|---|---|
|
||||
| `POST /api/auth/login` `refresh` · `GET /api/auth/invitation` · `POST /api/auth/register` | **no auth** |
|
||||
| `POST /api/auth/logout` · `GET /api/auth/me` · `/api/auth/sessions*` | authed |
|
||||
| `POST /api/auth/password` — change your OWN | authed (platform admins too) |
|
||||
| `GET /api/visits` · `GET /api/visits/stream` | authed |
|
||||
| `GET /api/visitors` · `GET /api/visitors/{id}/history` · `GET /api/visitors/{id}/image` · `GET /api/faces/{id}` | authed |
|
||||
| `PUT /api/visitors/{id}/profile` · `POST /api/purchases` | staff |
|
||||
@@ -477,6 +478,34 @@ deactivate them (§4); that revokes every session they hold.
|
||||
|
||||
---
|
||||
|
||||
### `POST /api/auth/password` — any signed-in account
|
||||
|
||||
Change your own password. Works for **every** account including a platform
|
||||
admin, who has no company and therefore cannot be reached by the team routes.
|
||||
|
||||
```json
|
||||
{ "current_password": "...", "new_password": "..." }
|
||||
```
|
||||
|
||||
```json
|
||||
{ "changed": true, "sessions_revoked": 3 }
|
||||
```
|
||||
|
||||
- **The current password is required.** An access token lives twelve hours and
|
||||
travels on shop-floor PCs and staff phones; without this a stolen one would
|
||||
own the account permanently rather than until it expires. Wrong current
|
||||
password is **403 `wrong_password`** and changes nothing.
|
||||
- **Every other session is revoked; the caller's is kept.** Somebody changing
|
||||
their password because they think it is known must not wonder whether the
|
||||
device that already had it is still signed in — and must not be signed out of
|
||||
the one in their hand while dealing with it.
|
||||
- A new password under the floor is **400**, and so is reusing the current one.
|
||||
|
||||
This is the route to use rather than asking an administrator. `POST
|
||||
/api/team/{id}/password` remains what a manager uses on somebody *else*.
|
||||
|
||||
---
|
||||
|
||||
## 4. The team
|
||||
|
||||
### `GET /api/team` — anyone in the company
|
||||
|
||||
41
CLAUDE.md
41
CLAUDE.md
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user