Skip to content

Part 5 — devices and key custody

const devices = await engine.listDevices();
// [{ deviceId, label, createdAt, revokedAt, current }]
// current: true for the device you are asking from

Show this list in your UI. A ghost device — one a malicious relay inserted to wait for a grant — is only detectable if somebody can see it. It is also gated: no device is handed a key without either proving it already holds one or being approved by a person. That is Part 14, and your app must provide a screen for this part of the linking flow. Key transparency, which would remove the human from the loop, is on the roadmap and does not exist yet.

The basic exchange is automatic. A new device registers its public keys on ArgalaEngine.open, and any device that already holds the keyring grants it during an ordinary sync (autoGrant, on by default).

an existing devicerelaynew deviceregister pubkeys + selfSig, open graph → status 'waiting'sync → sees the gap → is this device approved here?wraps every epoch to N's published pubkeysync → unwraps → status 'ok'

From the app’s point of view: the new device shows waiting until an existing device syncs, then flips to ok. Tell the user that: “open the app on your laptop to finish linking.”

The one step that is not automatic is the middle line. A device that has already written something the granting device could read is approved silently; anything else raises device.pending and waits for a person. See Part 14 — under linking: 'approve', a brand-new device has written nothing yet, so with no approval screen it sits in waiting and nobody can say why.

To drive the ceremony yourself, set autoGrant: false and call engine.grantPending(graphId) when you choose.

KeyStore
device:<deviceId> ECDH P-256 keypair — receives wrapped graph keys
sign:<deviceId> ECDSA P-256 keypair — proves authorship
keyring:<graphId> { epochs: {1: key, 2: key}, current: 2 }

Nothing in that list ever leaves the device except public halves.