Skip to content

(Apple) Sync companion app servers between same iCloud user devices #254

Description

@bgoncal

Problem statement

Every time a Home Assistant user installs the companion app on another Apple device (new iPhone, iPad, Mac, or a family hand-me-down signed into the same Apple Account), they have to set it up from scratch: discover or type the server URL, configure internal/external URLs and SSIDs, log in, grant permissions and re-tune settings. For users with several servers or several devices, this is repeated per device and per server.

Apple users already expect apps to "just be there" on a new device (passwords, Wi-Fi, app data via iCloud). The companion app doesn't meet that expectation, which adds friction at exactly the moment a user is trying to expand their use of Home Assistant.

Who is impacted: Apple-platform users with more than one device (iPhone + iPad + Mac is very common), users migrating to a new device, and users with multiple Home Assistant servers.

Why it matters to OHF: Reducing setup friction makes Home Assistant easier to adopt across a household's devices, and supports the goal of a polished, first-class companion app experience. It also gives us a chance to fix a long-standing issue where restoring/migrating devices produces cloned or broken mobile_app registrations.

Community signals

No response

Scope & Boundaries

In scope

  • Sync the list of servers and their server-level configuration between devices signed into the same Apple Account (iPhone, iPad, Mac; Apple Watch keeps getting it from its paired iPhone).
    • Server name, server identifier (UUID), internal URL, external URL, SSIDs / hardware addresses used for internal detection, user-facing server settings.
  • On first launch on a new device, offer "Continue with Home (found in iCloud)" instead of the onboarding flow.
  • Each device still registers itself with Core as its own device (see Foreseen solution).
  • An in-app opt-in/opt-out toggle for iCloud sync, and a way to stop syncing a specific server.

Out of scope

  • Syncing any device-specific data: webhook ID, webhook secret, cloudhook URL, remote UI URL, device ID, push token, sensors/notification categories, location settings.
  • Sharing servers across different Apple Accounts (Family Sharing) — separate opportunity.
  • Android / non-Apple platforms (could inspire a parallel effort with Google backup/Block Store, but not part of this bet).
  • Syncing dashboards, Assist pipelines, or other server-side data (already lives on the server).
  • Watch-only standalone setup changes.

Foreseen solution

Storage

  • Server config (non-secret): NSUbiquitousKeyValueStore or a CloudKit private database. Small payload, automatically available on all devices signed into the same iCloud account.
  • Credentials (secret): iCloud Keychain item with kSecAttrSynchronizable = true in the shared keychain access group. End-to-end encrypted by Apple, never touches our servers or plain iCloud storage.

Authentication — two phases

Phase 1 — Pre-configured, not pre-authenticated (low risk, ships first)

  • New device reads the synced server config and skips URL discovery/entry.
  • User authenticates on the new device via the normal HA login flow (same OAuth flow as today, just pre-pointed at the right server and URLs).
  • Result: one tap + login instead of the full onboarding. No new Core APIs needed.

Phase 2 — Pre-authenticated via device enrollment (needs Core support)

  • The existing device stores a synced bootstrap credential in iCloud Keychain.
  • The new device does not reuse that refresh token long-term. It uses it once to call a new Core endpoint (in the new companion apps integration) that exchanges it for a brand-new, device-bound refresh token (e.g. POST /api/companion/enroll, returning a new refresh token tied to the new device's client name).
  • Core records the new token as a separate session in the user's profile ("Bruno's iPad – iOS app"), so it can be revoked independently.
  • Core sends a notification to the user's other devices / persistent notification: "A new device signed in as Bruno via iCloud". Optional admin setting to disable iCloud enrollment entirely.
  • Reusing one shared refresh token across devices is explicitly rejected: revoking it would log out every device and Core couldn't tell devices apart.

Device registration on Core

  • Sync carries no registration data. On first launch each device performs its own registration (mobile_app today, the new companion integration going forward) with its own installation UUID, device name, model and push token.
  • Core creates a separate device + config entry + webhook per device, exactly like a fresh install today.
  • Core dedupes by installation/device identifier so restoring a backup or re-installing doesn't create clones.
  • The synced server UUID lets the app match the iCloud entry to the right server even if URLs differ.

Flow

New device launches
  └─ iCloud has servers? ── no ──► normal onboarding
        │ yes
        ▼
  "Continue with Home?"
        │
   Phase 1: login flow ─┐
   Phase 2: enroll with ├─► new device-bound refresh token
   synced bootstrap ────┘
        ▼
  Register device with Core (new webhook, device entry)
        ▼
  Ready — permissions & sensors set up per device

Risks & open questions

  • Security of pre-auth: anyone with access to a device signed into the same Apple Account (e.g. a shared family iPad) would get access to the user's HA. Mitigations: Phase 1 first, Phase 2 opt-in, notify on enrollment, require device passcode/biometrics before enrolling, admin kill-switch. Needs a security review.
  • Core API for token exchange: HA auth has no "mint a new refresh token from an existing one" flow today. Needs alignment with Core/auth owners (Paulus, Franck) on design and whether it belongs in the companion integration or in auth.
  • Refresh token lifecycle: what happens to the synced bootstrap token if the original device is removed or the token is revoked? Should the bootstrap token be a dedicated, short-lived/limited enrollment token rather than a real session token?
  • Data model refactor in the app: current server storage mixes server-level and device-level data; it must be split cleanly so device-specific data is never synced.
  • Conflict handling: two devices editing the same server config simultaneously, or a server deleted on one device — sync vs. local override semantics.
  • iCloud availability: users with iCloud Keychain / iCloud Drive off, Managed Apple Accounts, or Advanced Data Protection — make sure we degrade gracefully to normal onboarding.
  • Privacy: server URLs in iCloud KVS are not end-to-end encrypted unless ADP is on. Consider storing everything in iCloud Keychain instead.
  • Dependency on the new companion apps integration in Core for the Phase 2 endpoint and improved registration/dedupe.

Appetite

Medium overall.

  • Phase 1 (sync server config, login on new device): Small — ~1 cycle, iOS only, no Core changes.
  • Phase 2 (pre-auth enrollment + Core endpoint + notifications): Medium — ~1–2 cycles across iOS and Core, plus security review.

Execution issues

No response

Decision log

Date Decision Outcome
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions