Skip to content

Device pairing for the console: a verifier on keel's disk, the secret on the device — blocked on #648 #656

Description

@eaitbrahim

Option 1 of #634, which #634 shipped without and named as the right answer in the wrong order.

What #634 left open

#634 fixed the case where the browser closed and keel serve kept running: the session cookie now carries a Max-Age, so a token that is still valid stops being thrown away. It deliberately did not fix the case where keel serve restarts, because that one is a theorem rather than a design choice — after a restart, no client can present a credential the new run accepts unless the server persisted something across the restart.

What ships today for that case is honesty: the console distinguishes a refusal from an outage, and offers a field to paste the address (or just the token) keel printed. That works from a browser tab and from an installed app whose shell is still cached.

The tail it does not reach, recorded in #634's commit and repeated here so it is not lost: an installed app whose service-worker cache has been evicted — Safari does this after seven unused days — makes a tokenless network navigation and gets the server's plain-text refusal in a window with no address bar. The text is truthful and names the token; there is nowhere in that window to paste one. That is the case pairing exists for.

Why it was not built at #634

#648 is the declared prerequisite for every Phase B item and says in terms that nothing remote ships before it. A pairing credential's whole value is remote — it is what lets a phone on a mesh re-authorise with no operator in the loop. Shipping a long-lived, remotely-usable bearer secret before the pass that defines token issuance, expiry and brute-force posture off loopback is shipping the prize before the lock.

And it would change what keel serve --host warns about. Today: "The session token is the only thing in the way, and it travels in cleartext" — and that token dies with the process. A pairing secret in cleartext on a LAN is a credential that does not. Inside a WireGuard mesh that is fine; on a plain --host LAN it is a real downgrade, and #648 is where the difference between those two gets written down.

The shape to build, so the design is not re-derived

Acceptance

  • An installed PWA whose worker cache has been evicted, launched after a keel serve restart, reaches a usable state with no terminal and no address bar.
  • Reading keel's state directory yields no value that authenticates as a device.
  • keel devices lists and revokes; revocation takes effect on the next request.
  • The disjointness pin passes and no capability row is added.
  • keel link prerequisite: the remote-exposure security pass — bind opt-in, tunnel Host validation, token issuance off loopback #648 has landed, and this is written against the token posture that pass defines — not around it.
  • The --host warning is re-read against what this adds and is still true, or is rewritten to stay true.

Blocked on #648. Follows #634.

Activity

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions