Multi-Device Setup¶
Use multiple devices -- laptops, desktops, CI runners -- under a single did:keri identity. Each device gets its own keypair and its own delegated identity: a delegated inception (dip) naming your root as delegator, anchored in your root's key event log.
Prerequisites¶
- An initialized identity on the host device (
auths init) - Auths CLI installed on both devices
- Both devices on the same Wi-Fi network (for LAN mode), or a running registry server (for online mode)
Adding a second device¶
There are three paths:
| Approach | Command | When to use |
|---|---|---|
| Pairing | auths device pair (or auths pair) |
Default for most setups. Handles key exchange and delegation automatically. |
| Direct delegation | auths device add |
Delegate a device whose public key you already have — no pairing session. |
| Legacy linking | auths device link |
Compatibility with the pre-delegation attestation flow only. |
Pairing flow¶
Pairing uses X25519 ECDH key agreement with signature binding. The binding signature covers short_code || initiator_x25519_pubkey || device_x25519_pubkey, preventing replay and MITM attacks. The outcome is a KERI delegation: the joining device ends up with its own delegated identity anchored by yours.
LAN mode (default -- no server required)¶
1. Host device initiates pairing¶
The CLI starts an ephemeral HTTP server on your LAN IP and displays a QR code with a 6-character short code:
━━━ Auths Device Pairing (LAN) ━━━
Registry: http://192.168.8.183:54688
Identity: did:keri:EnXNx...
[QR CODE]
Scan the QR code above, or enter this code manually:
Z43-8JR
Capabilities: sign_commit
Expires: 20:23:07 (300s remaining)
(Press Ctrl+C to cancel)
2. Joining device enters the code¶
From another terminal or device:
The joiner discovers the host via mDNS, performs the ECDH key exchange, and the host anchors the new device's delegation in ~/.auths.
Code formatting is flexible
Dashes and spaces in the code are ignored. Z43-8JR, Z438JR, and z43 8jr all resolve to the same session.
Online mode (with relay server)¶
Use online mode when devices are not on the same network.
1. Start the registry server (if self-hosting)¶
The server binds to 0.0.0.0:3000 by default.
2. Host initiates pairing¶
3. Joiner enters the code¶
Both sides must use the same --registry URL
When pairing with a mobile device, use your machine's LAN IP rather than localhost.
Pairing command reference¶
| Flag | Default | Description |
|---|---|---|
--registry <URL> |
(omit for LAN mode) | Registry server URL; omit to use LAN mode |
--join <CODE> |
Join an existing session using the short code | |
--no-qr |
false |
Only show the short code, skip QR |
--expiry <SECONDS> |
300 |
Session TTL (5 minutes max) |
--capabilities <LIST> |
sign_commit |
Comma-separated capabilities to grant |
--offline |
false |
Render QR only, no network (testing only) |
Mode dispatch¶
| Command | Mode |
|---|---|
auths device pair |
LAN: local HTTP server + mDNS |
auths device pair --registry URL |
Online: registry relay |
auths device pair --join CODE |
LAN join: mDNS discovery |
auths device pair --join CODE --registry URL |
Online join: registry relay |
auths device pair --offline |
Offline: QR only, no server |
Direct delegation (auths device add)¶
When you already have the new device's public key (no pairing session), delegate it directly — the device becomes a delegated identifier of your identity:
This is the keripy-native, device-bound way to grant a device signing authority.
Manual linking (legacy)¶
The attestation-based flow predates KERI delegation and is kept for compatibility.
Prefer pairing or device add for new setups.
1. Import the device key on the new device¶
IDENTITY=$(auths id show | grep 'Identity:' | awk '{print $NF}')
auths key import \
--key-alias laptop-key \
--seed-file ~/device_key.seed \
--controller-did "$IDENTITY"
The seed file must contain exactly 32 bytes of raw Ed25519 key material. You will be prompted for a passphrase to encrypt the key before storing it in the platform keychain.
2. Link the device¶
auths device link \
--key my-key \
--device-key laptop-key \
--device "$DEVICE_DID" \
--note "Work Laptop" \
--expires-in 7776000
You will be prompted for passphrases for both the identity key and the device key, as the attestation requires dual signatures.
Optional flags for device link:
| Flag | Description |
|---|---|
--payload <PATH> |
Path to a JSON file with arbitrary payload data |
--schema <PATH> |
JSON schema to validate the payload (experimental) |
--expires-in <SECONDS> |
Attestation expiry |
--note <TEXT> |
Description for this device authorization |
--capabilities <LIST> |
Comma-separated permissions to grant |
3. Configure Git on the new device¶
git config --global gpg.format ssh
git config --global gpg.ssh.program auths-sign
git config --global user.signingKey "auths:laptop-key"
git config --global commit.gpgSign true
Commits from this device will now be signed by the same identity.
How attestations delegate trust (legacy flow)¶
When a device is linked (rather than delegated), Auths creates a device attestation -- a JSON document dual-signed by both the identity key and the device key. The attestation contains:
- The identity DID (
did:keri:...) as the issuer - The device DID (
did:key:z...) as the subject - The device's Ed25519 public key
- Granted capabilities (e.g.,
sign_commit) - Optional expiration timestamp
- Both signatures (identity and device)
The attestation is canonicalized with json-canon before signing, stored as a Git ref under refs/auths/, and can be verified by any party with access to the identity's Key Event Log.
Managing linked devices¶
List devices¶
Extend an expiring attestation¶
auths device extend \
--device "$DEVICE_DID" \
--expires-in 7776000 \
--key my-key \
--device-key laptop-key
Revoke a device¶
After revoking, remove the local keys:
Verify an attestation¶
The --attestation flag accepts a path to a device authorization JSON file, or - to read from stdin. You can optionally pass --signer or --signer-key to specify the expected signer.
Troubleshooting¶
"Short code not found"¶
The host has not initiated a session, the session expired (>5 minutes), or the code was entered incorrectly. Run auths device pair on the host first, then enter the code on the joining device within the expiry window.
"Could not connect" in LAN mode¶
- Verify both devices are on the same Wi-Fi network and subnet.
- Check firewall settings:
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstateon macOS. - Test connectivity with the curl command printed by the CLI.
- Check router AP isolation settings.
"No signing key found for identity"¶
The keychain has no key associated with the loaded identity DID:
Session expired¶
More than 5 minutes passed between initiation and joining. Run auths device pair again for a fresh code. Adjust the window with --expiry <SECONDS>.