Skip to content

Design account-wide devices: the Relay keeps no device list - #1473

Draft
nedtwigg wants to merge 4 commits into
mainfrom
issue-331-account-device-directory
Draft

nedtwigg wants to merge 4 commits into
mainfrom
issue-331-account-device-directory

Conversation

@nedtwigg

@nedtwigg nedtwigg commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Design only: this adds the account-wide devices design under ## Future in docs/specs/remote-security-model.md, part of the remote-trust-followups scope with Revocation propagation. No code changes.

  • The Relay keeps no device list. Each Burrow stays the authority on its own paired phones. Each stage is a new caller of BurrowService.revoke (shipped in Revoke a paired phone live, and keep an owner-local access log #1459) under a requester of its own.
  • Stage 1: passkey removal reaches the ACL. Hosted's account page already removes a passkey from the Relay; the Burrow will send the credential ids its records hold, the Relay will name which ones its account no longer has, and the Burrow revokes them by passkey target.
  • Stage 2: list and revoke from Pocket on each reachable paired Burrow over protocol-v1, by the shipped deviceIdFor id, behind a fresh presence proof.
  • A stage-1 revocation needs no passkey assertion. Revocation fails safe: a forged revocation can deny access but never grant it, unlike approving a connection, which fails dangerously. The reasoning is in the paired rationale file.

Refs #331

🤖 Generated with Claude Code

nedtwigg and others added 2 commits October 30, 2026 13:20
Issue #331 asked for an account-wide device list. The root constraint is
the trust model: the ACL lives only on each Burrow and the Relay never
sees a Client static or lists a deliveryId, so no Relay-held directory
can name a Burrow's records without reversing those rules.

Record the design under remote-security-model.md ## Future as part of
remote-trust-followups, built on the Burrow-local revocation entry point:
the managed identities stay the passkey (account-wide, Relay-held) and the
ACL record (per Burrow), never merged; stage 1 makes Hosted's existing
passkey removal reach every Burrow's ACL as a revoke-only answer to the
credential ids the Burrow asks about; stage 2 lists and revokes records
from Pocket over protocol-v1 on reachable Burrows, behind a fresh proof.
Whether stage 1 carries a passkey assertion is left for a decision, with
the reasoning in the rationale.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ned decided a Relay-named revocation needs no passkey assertion:
revocation fails safe, unlike approving a connection, which fails
dangerously. State it as the rule and move the reasoning to the
rationale.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Deploying mouseterm with  Cloudflare Pages  Cloudflare Pages

Latest commit: 4ff0eaa
Status: ✅  Deploy successful!
Preview URL: https://9f80445c.mouseterm.pages.dev
Branch Preview URL: https://issue-331-account-device-dir.mouseterm.pages.dev

View logs

nedtwigg and others added 2 commits October 30, 2026 22:33
Take #1459's Revocation propagation text, since BurrowService.revoke now exists, and keep this branch's Account-wide devices design after it. Resolve scripts/spec-word-budgets.json by taking the larger budget per spec, then ratchet docs/specs/remote-security-model.md, since both sides added words.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Revocation shipped (#1459) as BurrowService.revoke with a Client-static
or passkey target, a REVOCATION_REQUESTERS member, and a revoked log
entry. Point the design at it instead of describing a hypothetical one:
stage 1 is the passkey target's first non-test caller, stage 2 revokes by
the shipped deviceIdFor id as dor remote revoke does (dropping the
invented per-response index), and last seen is the access log's. Revocation
propagation now points at the stages rather than restating the caller.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@dormouse-bot dormouse-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new section has two cross-spec links that a reader following them would find broken or circular; details inline.

**The Relay will hold no device directory**: no record's label, `deliveryId`, approval time, or `deviceIdFor` id reaches the Relay, which sees only stage 2's ciphertext ([Burrow Authorization](#burrow-authorization); rationale). The account view is assembled from what each side already holds, in two stages:

1. **Passkey removal reaches the ACL.** Hosted's account page already removes a passkey from the Relay, ending its sessions and sign-ins (`docs/specs/hosted.md` -> "Burrow enrollment"), while every Burrow keeps its records active. On its `burrowToken`, at socket open and on a nudge frame after any removal, the Burrow will send the credential ids its active records hold, and the Relay answer which of them its account no longer holds; the Burrow revokes each by its passkey target, an offline one at its next connection. **A Relay-named revocation may only revoke** — never create, restore, or edit a record — so a lying Relay costs re-pairing, which is availability ([Goals](#goals); rationale).
2. **Per-record list and revoke from Pocket**, on each online Burrow it is paired with, over protocol-v1 (`docs/specs/remote-api.md` -> "Future"): each record's mapped label, `deviceIdFor` id, approval time, last seen ([Access log](#access-log)), and whether it is the caller's, revoked by that id as `dor remote revoke` is, never by a static or `deliveryId`. **Revoking takes a fresh presence proof, never a window ride.** An unreachable Burrow is shown as one, stage 1 being the lever that reaches it.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stage 2 sends list and revoke messages over protocol-v1 and points at docs/specs/remote-api.md -> "Future", but that section (remote-api-remainder) has no stage for them. It covers browser surfaces, command replay, grants, and VR, and nothing about the ACL or revocation. Meanwhile remote-api's protocol-v1 scope says "Must restrict it to terminal listing, one attachment per session, and terminal input/resize", with everything else staged in its Future. So a reader following the pointer finds nothing, and the one spec that owns what a Client speaks has no record of these two methods. Add a stage to remote-api-remainder that names them and links back here, or rewrite the pointer to say the messages aren't staged there yet.

## Future

**Scope: remote-trust-followups** — [Device verification](#device-verification) and [Revocation propagation](#revocation-propagation).
**Scope: remote-trust-followups** — [Device verification](#device-verification), [Revocation propagation](#revocation-propagation), then [Account-wide devices](#account-wide-devices), which builds on it.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ordering here goes in a circle. This line says Account-wide devices builds on Revocation propagation, but Revocation propagation now says Account-wide devices "stages both", and Account-wide devices opens with "One design with Revocation propagation, not two". If they are one design, the scope can list it once:

Suggested change
**Scope: remote-trust-followups** — [Device verification](#device-verification), [Revocation propagation](#revocation-propagation), then [Account-wide devices](#account-wide-devices), which builds on it.
**Scope: remote-trust-followups** — [Device verification](#device-verification), and [Account-wide devices](#account-wide-devices), which stages [Revocation propagation](#revocation-propagation).

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants