Skip to main content

Pairing & Encryption

Contop uses QR code pairing for out-of-band key exchange and WebRTC for end-to-end encrypted communication.

QR Code Pairing​

The QR code serves as a secure out-of-band channel for exchanging connection details and cryptographic material.

QR Payload​

The QR code contains a compact JSON payload with short keys for ~40% smaller QR codes:

KeyFull NameRequiredDescription
ttokenYesPairing token string
ddtls_fingerprintYesSHA-256 fingerprint of server's DTLS certificate
hhostYesServer LAN IP
pportYesServer port
eexpires_atYesToken expiration timestamp (ISO 8601)
cconnection_typeYes"permanent" or "temp"
ggemini_api_keyNoGemini API key for mobile use (omitted if empty or in subscription mode)
oopenai_api_keyNoOpenAI API key (if configured)
aanthropic_api_keyNoAnthropic API key (if configured)
ropenrouter_api_keyNoOpenRouter API key (if configured)
tstailscale_ipNoTailscale IP (if available)
ssignaling_urlNoSignaling URL (temp connections only)
paprovider_authNoCompact subscription flags (pa.g, pa.a, pa.o = "sub")

Pairing requires at least one API key or at least one provider configured in subscription mode. When a provider is in subscription mode, its API key is omitted from the QR payload (the mobile app doesn't need it - requests route through the desktop's CLI proxy instead). This means subscription-only users can pair without configuring any API keys.

DTLS Certificate​

  • Ephemeral self-signed X.509 certificate (RSA 2048)
  • SHA-256 fingerprint in AB:CD:EF:... format
  • Generated via asyncio.to_thread() to avoid blocking
  • Fingerprint is embedded in the QR code for verification during WebRTC handshake

Token Management​

Token Types​

TypeTTLPersistenceUse Case
Permanent30 days~/.contop/tokens.json on diskYour personal devices
Temporary4 hoursIn-memory onlyGuest access, demos

Token Lifecycle​

  1. Generation - POST /api/pair creates a token with metadata
  2. Validation - Token verified on every WebRTC signaling connection
  3. Renewal - Permanent tokens reused if still valid (QR regenerated with fresh network info)
  4. Revocation - DELETE /api/pair or per-device DELETE /api/pair?device_id=...
  5. Single active per device - Auto-revokes old token when same device_id re-pairs
  6. Per-device revoke - DELETE /api/pair?device_id=... revokes a specific device's token and force-disconnects the session

Token Storage​

  • Server: ~/.contop/tokens.json with 0o600 permissions (owner-only read/write)
  • Mobile: OS secure enclave via expo-secure-store (Keychain on iOS, Keystore on Android) - never in AsyncStorage

WebRTC Encryption​

All data between phone and desktop is encrypted end-to-end:

ChannelEncryptionKey Exchange
Data channelsDTLS 1.2+Certificate fingerprint verified via QR
Video streamSRTPKeys derived from DTLS handshake

Certificate Fingerprint Verification​

During the WebRTC handshake, the mobile app verifies that the server's DTLS certificate fingerprint matches the one embedded in the QR code. This prevents man-in-the-middle attacks even if the signaling channel is compromised.

Network Detection​

The server detects available network paths for the QR code:

  1. LAN IP - Socket-based detection of local network address
  2. Tailscale IP - tailscale ip -4 CLI or 100.x.y.z interface scan
  3. Tunnel URL - Cloudflare Tunnel URL (started on demand)

The mobile app uses connectSignalingWithFallback() to try LAN → Tailscale → Tunnel in order.

Mobile Device Metadata​

The mobile app sends device metadata during pairing:

  • Device name - From expo-device (e.g., "iPhone 15 Pro")
  • Location - GPS from expo-location (if permission granted)

This metadata is stored alongside the token and displayed in the desktop's device management panel.


Related: Connection Methods · Device Management · REST API - Pairing