Phase A — Sessions that end: revocation cascade and egress counter #2

Closed
opened 2026-09-14 13:55:21 +01:00 by cruelacid · 3 comments
Owner

Part 1 of 3 of the sessions/device-roster plan (14 Sep 2026). Fixes: signing a session out on one device left the device connected and counted elsewhere.

Design

  • sid in access, identity and shard tokens; identity authenticate() refuses revoked sessions (SESSION_REVOKED) for access tokens.
  • Identity POSTs /api/admin/session-revocations to each shard (DIRECTORY_TOKEN bearer + identity-signed typ:'revocations' JWT) before every pull and at once after every revoke; whole window (REVOCATION_WINDOW_DAYS 8), idempotent, coalesced with one queued follow-up.
  • Shard persists revoked_sessions, one sessionRefused() predicate for HTTP, upgrade, /auth/session, /auth/join and the message path; closes with 4005 WS_CLOSE_SIGNED_OUT; a pre-sid token gets 4005 too.
  • Plugin on 4005: stop reconnecting, ask identity before deciding, sign out only on an unrecoverable 401; generation guard against the same-install re-sign-in race; pane loaders route identity 401s through recoverIdentitySession().
  • Egress counter: account_egress_daily, GET /api/admin/egress, egress on the admin account route, nectenda_account_egress_30d_bytes, /api/health egressHot + Kuma keyword monitor.

Checkpoint

  • pnpm -r typecheck, pnpm test, pnpm lint, mirror --check
  • multi-vault e2e green incl. the new sign-out-elsewhere test
  • mutation checks listed in the plan each fail when inverted
  • docs updated (accounts, identity, key-storage, security-model, self-hosting, architecture-capacity, commercial-model join term, support-runbook, manual-testing, plan-phase13/14, launch-readiness)
  • deploy identity → shard → plugin into both vaults
  • live: sign A out from B → A's notice within ~60 s; eu1 logs the refusal; A leaves B's list
  • live: /api/admin/egress answers; /api/health "egressHot":[]; Kuma monitor green; floor=1 turns it red; revert
Part 1 of 3 of the sessions/device-roster plan (14 Sep 2026). Fixes: signing a session out on one device left the device connected and counted elsewhere. ## Design - `sid` in access, identity and shard tokens; identity `authenticate()` refuses revoked sessions (`SESSION_REVOKED`) for access tokens. - Identity POSTs `/api/admin/session-revocations` to each shard (DIRECTORY_TOKEN bearer + identity-signed `typ:'revocations'` JWT) before every pull and at once after every revoke; whole window (`REVOCATION_WINDOW_DAYS` 8), idempotent, coalesced with one queued follow-up. - Shard persists `revoked_sessions`, one `sessionRefused()` predicate for HTTP, upgrade, `/auth/session`, `/auth/join` and the message path; closes with 4005 `WS_CLOSE_SIGNED_OUT`; a pre-`sid` token gets 4005 too. - Plugin on 4005: stop reconnecting, ask identity before deciding, sign out only on an unrecoverable 401; generation guard against the same-install re-sign-in race; pane loaders route identity 401s through `recoverIdentitySession()`. - Egress counter: `account_egress_daily`, `GET /api/admin/egress`, `egress` on the admin account route, `nectenda_account_egress_30d_bytes`, `/api/health` `egressHot` + Kuma keyword monitor. ## Checkpoint - [ ] `pnpm -r typecheck`, `pnpm test`, `pnpm lint`, mirror `--check` - [ ] multi-vault e2e green incl. the new sign-out-elsewhere test - [ ] mutation checks listed in the plan each fail when inverted - [ ] docs updated (accounts, identity, key-storage, security-model, self-hosting, architecture-capacity, commercial-model join term, support-runbook, manual-testing, plan-phase13/14, launch-readiness) - [ ] deploy identity → shard → plugin into both vaults - [ ] live: sign A out from B → A's notice within ~60 s; eu1 logs the refusal; A leaves B's list - [ ] live: `/api/admin/egress` answers; `/api/health` `"egressHot":[]`; Kuma monitor green; floor=1 turns it red; revert
Author
Owner

Landed as 934d15e and deployed 14 September 2026 (identity → eu1 → plugin into both local vaults).

  • pnpm -r typecheck, pnpm test (803 unit tests), pnpm lint, mirror --check
  • multi-vault e2e green (runs 5, 6 and the baseline b2); the recurring failure was traced to a pre-existing load-sensitive flake, filed as #3
  • 13 mutation checks each fail when inverted
  • docs updated (accounts, identity, key-storage, self-hosting, architecture-capacity, commercial-model join term, support-runbook, manual-testing §12c, plan-phase13/14, deploy)
  • deployed identity (Applied migration 4) → shard (Applied migration 5, 6) → plugin (sha a77b028c…, verified byte-identical to source)
  • live: first push took 12 ended sessions (Sessions signed out received:12 added:12 closed:0); identity /api/health revocationsOk:true
  • live: GET /api/admin/egress and egress on the admin account route answer; /api/health shows "egressHot":[]; Kuma sync eu1 egress added and published; EGRESS_ALERT_FLOOR_BYTES=1 with a synthetic row turned it red, revert cleared it, env file restored byte-identical
  • live: sign vault A out from vault B → A's notice within ~60 s (needs both vaults reloaded onto the new build; manual-testing §12c)

Previous pins kept as /srv/identity/.env.before-934d15e and /srv/nectenda/.env.before-934d15e.

Landed as `934d15e` and deployed 14 September 2026 (identity → eu1 → plugin into both local vaults). - [x] `pnpm -r typecheck`, `pnpm test` (803 unit tests), `pnpm lint`, mirror `--check` - [x] multi-vault e2e green (runs 5, 6 and the baseline b2); the recurring failure was traced to a **pre-existing** load-sensitive flake, filed as #3 - [x] 13 mutation checks each fail when inverted - [x] docs updated (accounts, identity, key-storage, self-hosting, architecture-capacity, commercial-model join term, support-runbook, manual-testing §12c, plan-phase13/14, deploy) - [x] deployed identity (`Applied migration 4`) → shard (`Applied migration 5`, `6`) → plugin (sha `a77b028c…`, verified byte-identical to source) - [x] live: first push took 12 ended sessions (`Sessions signed out received:12 added:12 closed:0`); identity `/api/health` `revocationsOk:true` - [x] live: `GET /api/admin/egress` and `egress` on the admin account route answer; `/api/health` shows `"egressHot":[]`; Kuma `sync eu1 egress` added and published; `EGRESS_ALERT_FLOOR_BYTES=1` with a synthetic row turned it red, revert cleared it, env file restored byte-identical - [ ] live: sign vault A out from vault B → A's notice within ~60 s (needs both vaults reloaded onto the new build; manual-testing §12c) Previous pins kept as `/srv/identity/.env.before-934d15e` and `/srv/nectenda/.env.before-934d15e`.
Author
Owner

Follow-up deployed: eu1 now on 7f88efa. A vault still on the old plugin was refused with 4005 once a second (accepted upgrade resets its backoff); pre-sid tokens are now refused at the handshake and back off to 30 s — seen live: 3 refusals in the minute after the deploy instead of ~60. Identity stays on 934d15e (dff14c2 is docs only).

Follow-up deployed: eu1 now on 7f88efa. A vault still on the old plugin was refused with 4005 once a second (accepted upgrade resets its backoff); pre-sid tokens are now refused at the handshake and back off to 30 s — seen live: 3 refusals in the minute after the deploy instead of ~60. Identity stays on 934d15e (dff14c2 is docs only).
Author
Owner

Live check done by the user: signing the other device out from Signed-in devices signed it out within a minute, and signing back in on itself came back cleanly. Phase A checkpoint complete.

Live check done by the user: signing the other device out from Signed-in devices signed it out within a minute, and signing back in on itself came back cleanly. Phase A checkpoint complete.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Nectenda/nectenda#2
No description provided.