Account page: change your password, or sign out everywhere else

Family idea #5105, practice 4. Either action signs the account out of every
other browser and unlinks every device. The browser that made the change stays
signed in.

- POST /api/auth/password needs the current password. A wrong one returns 403,
  not 401, so this browser doesn't read as signed out, and it counts against the
  sign-in throttle. A short new password returns 400.
- POST /api/auth/sign-out-elsewhere does the same sign-out without a password
  change. Called from a device, it keeps that device linked.
- _sign_out_elsewhere moves session_epoch on and deletes device tokens. The
  reset route now uses it too, keeping no device.
- The page is renamed from "Linked devices" to "Account", in the router title
  and both nav entries. Its sections are Linked devices, Password (one short
  line, then the form) and Sessions (a single "Sign out everywhere else" row in
  the device rows' style), per preference 188: one line each, no paragraphs.
- docs/public-hosting.md says how sessions end, and why a browser session isn't
  listed the way a device is: it is a signed cookie, ended by moving the epoch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 10:22:16 -04:00
co-authored by Claude Opus 5.5
parent 1dd6fc1e20
commit bb591871a4
10 changed files with 293 additions and 13 deletions
+6
View File
@@ -113,6 +113,12 @@ docker run --rm -v inkwell-data:/d -v "$PWD":/out alpine tar czf /out/media.tgz
on a note shared with you can't run script in your session.
- **Session cookies are `HttpOnly` and `SameSite=Lax`**, which is also what stands in
for CSRF protection: a `Lax` cookie is not sent on a cross-site POST.
- **Sessions can be ended from the Account page.** Changing your password there needs
the current one. It signs you out of every other browser and unlinks every app,
and you stay signed in where you made the change. **Sign out everywhere else**
does the same without changing the password. A browser session doesn't appear in
a list the way a linked app does: it is a signed cookie in that browser, ended by
moving the account on rather than by deleting a row.
## Email and forgotten passwords