A Machine

The credentials that prove a machine is one signed in to its account: its machine key and the assertion it signs with it, the sealing key what's sent to it is sealed to, and the device code of its login.

The machine key

A key pair a machine makes when it signs in. The account service keeps only the public half, so nothing it holds, or loses, signs in as the machine.

  • Proves: this machine is one signed in to its account.
  • Made by: lnk auth login, on the machine: an Ed25519 key pair from the system's random source. The login sends the public half; a person approves it in the browser (the device code), and the account service keeps it with the machine's id. No private half ever crosses a network.
  • Held by: the accounts plugin alone. In the Keychain on a Mac (machine-key, as Secrets in the Keychain keeps every item), else in ~/.lnk/config.toml, mode 600.
  • Travels: never. It signs a machine assertion for each access token.
  • Lasts: until the machine is signed out.
  • Revoked: by lnk auth logout on the machine, lnk iam machine remove <machine> from any other of the account's, or in the browser. The account service deletes the public half, and every signature after is refused. Access tokens already made last out their life.
  • May: get access tokens for its account, for any audience and scope a machine may have. Nothing else takes it or its signature.

A box's machine key

lnk box create signs in the box it made the same way, without a browser: the box makes its own pair and sends back the public half, and this machine adds it to the account with an access token (lnk auth key, lnk iam machine add, then lnk auth login --granted on the box).

The sealing key

What the account service seals a connection's token to, when you connect a connection to one of this machine's agents in the browser, so only this machine opens it as the browser delivers it over the remote relay. The account service keeps neither the token nor its sealed value.

  • Proves: nothing: it only opens what was sealed to it.
  • Made by: the remote plugin, the first time it takes actions (lnk remote start --actions, lnk remote watch --actions): an X25519 key pair from the system's random source, link-secret-value's own (Recipient), kept rather than made for one transfer, so a connection connect reaches the same recipient across reconnects. It is separate from the machine key, which only signs.
  • Held by: the remote plugin alone. In the Keychain on a Mac (remote/sealing-key), else in ~/.lnk/remote/sealing-key, mode 600.
  • Travels: never. Its public half goes with every report that takes actions (seal_to), which this machine's access token carries, and the account service keeps it with the machine.
  • Lasts: until the plugin is uninstalled with its sealing-key part, or the file is removed: the plugin makes another, and a connect sealed to the old one fails, saying to ask again.
  • May: open what the account service sealed to this machine, for the agent and kind of action it was sealed for: HPKE (RFC 9180) in its base mode, X25519, HKDF-SHA256 and ChaCha20-Poly1305, as link-secret-value seals every value.
  • Made once: under a lock beside it, so two first runs at once keep one key; a Keychain that can't be read (locked, or asking for a person) is an error, and a key is never made over one that's there.

Sealed for this machine alone

What's sealed names this machine's id at the account service with the agent (<machine id>/<agent>), so a copy of its settings on another machine, signed in as that one, opens nothing sealed for this one.

The machine assertion

What a machine sends the account service for an access token: a JWT signed with its machine key, good for one request.

PartHolds
Headeralg EdDSA, typ machine+jwt, and nothing else
issThe machine's id
subThe account's id, acct-<32 hex>
audThe account service's origin, https://accounts.example.com
resourceThe audience of the access token asked for
scopeIts scope
iat, expWhen it was made, and at most 60 seconds later
jti16 random bytes, base64url

The account service checks the signature with the machine's public half, aud its own origin, exp at most 60 seconds after iat, and the jti unseen while the assertion could be taken, so one sent twice is refused. A machine's clock may be 2 minutes off either way: iat no more than that ahead, exp no more than that behind, and the jti is kept that much longer. A machine signed out has no public half there, and is refused.

The device code

What a machine and a person share for one login, as OAuth's device flow does it.

  • Proves: the machine collecting a login is the one that began it (the device code), and the person approving it is looking at that machine's login (the user code).
  • Made by: the account service, when lnk auth login begins.
  • Held by: the machine (the device code, which no browser sees), and the person (the user code, 8 letters, which lnk auth login prints for them to check in the browser).
  • Travels: the device code from the machine to the account service only; the user code by the person's eyes.
  • Lasts: 10 minutes, and is used once.
  • Revoked: by Deny in the browser, or by expiring.
  • May: add one machine to the account of the person who approved it.