Skip to content

Invite codes and device pairing

Invite codes and device pairing

Status: Delivered
CAS: CAS-583
Delivered: 2026-04-25
PRs: #188 (F1 invite generation UI), #190 (F1–B3 invite backend + deep-link redemption)

What’s new

Casaconomy now supports a cryptographically secure invite system for adding a second device to an existing vault (device pairing) and for joining an existing group as a new participant. Invites are short alphanumeric codes generated on the issuing device and accepted on the new device — the relay that carries them can never synthesize or replay one.

How to use it

Generating an invite (issuer side):

  1. Open the invite screen and tap Generate invite.
  2. The app displays a short Crockford-Base32 code and a deep link QR code.
  3. The invite is valid for a limited window; the expiry is shown on screen.
  4. Share the code or QR with the person or device joining.
  5. The code can be cancelled at any time before it is redeemed.

Accepting an invite (acceptor side):

  1. On the new device, open the deep link or manually enter the invite code.
  2. The app verifies the issuer’s signature, performs an X25519 ECDH handshake, and derives a shared session key via HKDF-SHA256.
  3. The issuer sends an encrypted identity bundle (XSalsa20-Poly1305 AEAD) over the WebSocket relay channel.
  4. On successful decryption, all keys are persisted to the acceptor’s keystore and the device is fully paired — no further manual steps required.

What changed under the hood

  • InviteCode type — new domain type with a Crockford-Base32 codec that avoids ambiguous characters (I/1, O/0).
  • Relay integrationPOST /invites/{code} to publish and GET /invites/{code} to claim; the relay is treated as an untrusted message bus and never sees plaintext.
  • services/invite_service.rs — core of the device-pairing protocol:
    • Issuer path (invite_device_start): generates ephemeral X25519 keypair, signs an invite manifest with the device’s long-term Ed25519 key, publishes to relay, then waits over WebSocket for the acceptor’s ephemeral key to complete the ECDH.
    • Acceptor path (invite_device_accept): fetches and verifies the signed manifest, sends its own ephemeral key, derives the HKDF session key, decrypts the identity bundle, and imports the keys into the local keystore.
  • New Tauri commandsinvite_device_start, invite_device_cancel, invite_device_accept; progress reported on the invite://progress event channel.
  • encryption/keystore.rs — added import_symmetric_key and import_signing_keypair for the acceptor to persist received key material.
  • Invite generation UI — new screen with code display, QR code, expiry countdown, and cancel action.
  • Deep-link handlercasaconomy://invite/{code} URL scheme routes the acceptor into the redemption flow with the code pre-filled.

Why we built it

Without a secure pairing mechanism, adding a second device or new group member requires manual key export and import — error-prone and opaque to non-technical users. The invite code system makes onboarding a second device a single short-code exchange while keeping the relay server completely blind to the key material it carries. This is the foundational prerequisite for the full multi-device onboarding flow (CAS-149).

Known limitations / follow-on work

  • End-to-end smoke test across two local app instances is deferred to CAS-591.
  • Group join flow (Flow B — new user joining an existing group) shares the same transport but uses a different key exchange; the UI for that path is not yet wired up.
  • The relay is currently a Cloudflare Worker; failover and rate-limiting are not yet hardened for production traffic.
  • Deep-link handling requires casaconomy:// URL scheme to be registered on the OS; this is only tested on macOS so far.