Skip to content

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

auths device pair

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:

auths device pair --join Z43-8JR

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)

cargo run --package auths-registry-server -- --cors

The server binds to 0.0.0.0:3000 by default.

2. Host initiates pairing

auths device pair --registry http://localhost:3000

3. Joiner enters the code

auths device pair --join Z43-8JR --registry http://localhost:3000

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:

auths device add --help    # see the flags for your version

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.

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

auths device list
auths device list --include-revoked

Extend an expiring attestation

auths device extend \
  --device "$DEVICE_DID" \
  --expires-in 7776000 \
  --key my-key \
  --device-key laptop-key

Revoke a device

auths device revoke \
  --device "$DEVICE_DID" \
  --key my-key \
  --note "Laptop retired"

After revoking, remove the local keys:

auths key delete --alias laptop-key

Verify an attestation

auths device verify --attestation path/to/attestation.json

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

  1. Verify both devices are on the same Wi-Fi network and subnet.
  2. Check firewall settings: sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate on macOS.
  3. Test connectivity with the curl command printed by the CLI.
  4. Check router AP isolation settings.

"No signing key found for identity"

The keychain has no key associated with the loaded identity DID:

auths key list
auths init --force   # Re-initialize if needed

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>.