Skip to content

Connecting to a machine

Approving a computer: the 6-digit check

When you approve a computer, two keys are swapped: your browser key goes to the computer, and the computer's ID goes to your browser. Our website carries both. So how do you know we (or anyone in between) didn't swap them for fakes?

Both screens show a 6-digit pairing code made from both keys. If anything was swapped, the codes come out different.

  your browser                     your computer
  +---------------------+          +---------------------+
  | Pairing code        |          | Pairing code:       |
  |    482 190          |   same?  |    482 190          |
  +---------------------+          | Does your browser   |
                                   | show this? [y/N] y  |
                                   +---------------------+

Only after you type y on the computer itself does it start trusting your browser.

Connecting: the locked conversation

 you click Connect
      |
      v
 browser --(1) "connect me to home-pc"--> website: is this YOUR computer?
                                          yes -> tells home-pc: "a browser wants you"
 home-pc opens a second line out to the website
 website joins the two lines together
      |
      v
 browser <========== locked conversation ==========> home-pc
   checks: "is this really home-pc?"      checks: "is this a browser I approved?"
   (its ID must match the one you           (your key must be on its list)
    approved)

Everything you type and everything that comes back is locked by your browser and your computer, not by us. We pass along the locked pieces.

If something's wrong

  • Your computer's ID doesn't match: your browser stops and warns you. It never quietly trusts a new ID.
  • Your browser isn't on the computer's list: the computer refuses ("Login failed").
  • Someone steals the computer's connection token: they still can't pretend to be your computer, because they don't have its ID key.

Enrolment (device-code flow + pairing code)

 roamd login               hub                        browser (logged in)
 -----------               ---                        -------------------
 create host key H (Ed25519)
 register H, get a short code  ------>
 print approve link                                   open link, see
                                                      machine name + fp(H)
                                                      approve: send B.pub
                                                      pin fp(H) in vault
 collect B.pub + device token <------
 pairing code = 6 digits from SHA-256 over fp(H) and fp(B)
 user compares with browser, types y
 only then: trust B.pub, save settings (sealed)

If the hub substituted H or B, the two sides would compute different pairing codes. The user rejects, and nothing is written. Approval codes are short-lived, single-use and rate-limited.

Tunnel and session setup

 roamd run --(outbound TLS WebSocket, device token)--> hub  (kept open)
 browser --(TLS WebSocket, session cookie, origin check)--> hub
    hub: does this account own the machine? is it online?
    hub asks the machine to open a second stream
 hub splices the two streams (bytes only)
 browser SSH client <==== SSH, end to end ====> roamd SSH server
  • Browser side: the machine's host key must match the pinned identity in the vault. There is no silent trust-on-first-use. Authentication uses the vault's Ed25519 key.
  • Machine side: only keys the user confirmed on this machine are accepted.
  • Algorithms: post-quantum hybrid key exchange (ML-KEM-768 + X25519), falling back to Curve25519; ChaCha20-Poly1305 or AES-GCM; strict key exchange.

What the hub can do if it's compromised

Attack Outcome
Read or change the shell session No: SSH is end to end, and changes break its integrity check
Pose as the machine with a stolen device token Browser refuses: no host private key, pin mismatch
Add its own key to the machine No: only keys confirmed on the machine via matching pairing codes
Deny or drop service Yes (it's the relay)
Serve malicious web-app code Possible: see limits

Tunnel hardening (agent)

The agent only talks to the hub over HTTPS. It validates and size-limits everything the hub sends, limits how many streams can be open at once, drops a hub that goes silent, and reconnects with randomised back-off. If the hub rejects its token, roamd run stops.