[GH-ISSUE #12] Different homes, same Apple TV name, wrong credentials --> Server Identity Mismatch. #10

Closed
opened 2026-03-03 16:44:54 +03:00 by kerem · 2 comments
Owner

Originally created by @awjoyce on GitHub (Feb 7, 2026).
Original GitHub issue: https://github.com/nickustinov/itsytv-macos/issues/12

Originally assigned to: @nickustinov on GitHub.

Observed that when I pair a TV in one home, the system seems to think it is paired with the TV that has the same name in another home.
Analysis from Claude on what might be happening when switching between homes with TVs named the same.

Here's the diagnosis. Yes, this is a confirmed bug. The root cause is that device identity is keyed by the Bonjour
service name, which is the user-visible name (e.g., "Living Room"), not a unique hardware identifier.

The data flow

  1. Discovery (DeviceDiscovery.swift:78-79): The AppleTVDevice is created with id: service.name — the Bonjour service
    name is both the id and the name:
    let device = AppleTVDevice(
    id: service.name,
    name: service.name,
    ...
    )
  2. Credential save (AppleTVManager.swift:286): After pairing, credentials are saved keyed by connectedDeviceName
    (which equals device.name = service.name):
    try KeychainStorage.save(credentials: credentials, for: deviceName)
  3. Credential load (AppleTVManager.swift:95): On connect, credentials are loaded by device.id (also service.name):
    if let credentials = KeychainStorage.load(for: device.id) {
  4. Pair-verify (PairVerify.swift:107): During verification, the server's identity is checked against the stored
    credentials:
    guard serverID == credentials.serverID else {
    throw Error.identityMismatch // <-- THIS IS YOUR ERROR
    }

What happens with same-named Apple TVs

When you have "Living Room" in Home A and "Living Room" in Home B:

  1. You pair with Home A's "Living Room" → credentials (including Home A's serverID and serverLTPK) saved under
    Keychain key "Living Room"
  2. You move to Home B's network → Bonjour discovers Home B's "Living Room"
  3. The app creates AppleTVDevice(id: "Living Room", ...) — same ID
  4. KeychainStorage.load(for: "Living Room") returns Home A's credentials
  5. Pair-verify starts, Home B's Apple TV sends its server identity
  6. PairVerify.processAndProve compares Home B's server ID against Home A's stored credentials.serverID → mismatch →
    Error.identityMismatch → "Server identity mismatch"

The fix

The Bonjour TXT record for _companion-link._tcp includes a unique device identifier (commonly the rpBA or
UniqueIdentifier field) that distinguishes hardware regardless of user-assigned name. The device ID should be derived
from one of these unique TXT record fields instead of service.name. This would make the Keychain key unique per
physical device rather than per display name.

Originally created by @awjoyce on GitHub (Feb 7, 2026). Original GitHub issue: https://github.com/nickustinov/itsytv-macos/issues/12 Originally assigned to: @nickustinov on GitHub. Observed that when I pair a TV in one home, the system seems to think it is paired with the TV that has the same name in another home. Analysis from Claude on what might be happening when switching between homes with TVs named the same. Here's the diagnosis. Yes, this is a confirmed bug. The root cause is that device identity is keyed by the Bonjour service name, which is the user-visible name (e.g., "Living Room"), not a unique hardware identifier. The data flow 1. Discovery (DeviceDiscovery.swift:78-79): The AppleTVDevice is created with id: service.name — the Bonjour service name is both the id and the name: let device = AppleTVDevice( id: service.name, name: service.name, ... ) 2. Credential save (AppleTVManager.swift:286): After pairing, credentials are saved keyed by connectedDeviceName (which equals device.name = service.name): try KeychainStorage.save(credentials: credentials, for: deviceName) 3. Credential load (AppleTVManager.swift:95): On connect, credentials are loaded by device.id (also service.name): if let credentials = KeychainStorage.load(for: device.id) { 4. Pair-verify (PairVerify.swift:107): During verification, the server's identity is checked against the stored credentials: guard serverID == credentials.serverID else { throw Error.identityMismatch // <-- THIS IS YOUR ERROR } What happens with same-named Apple TVs When you have "Living Room" in Home A and "Living Room" in Home B: 1. You pair with Home A's "Living Room" → credentials (including Home A's serverID and serverLTPK) saved under Keychain key "Living Room" 2. You move to Home B's network → Bonjour discovers Home B's "Living Room" 3. The app creates AppleTVDevice(id: "Living Room", ...) — same ID 4. KeychainStorage.load(for: "Living Room") returns Home A's credentials 5. Pair-verify starts, Home B's Apple TV sends its server identity 6. PairVerify.processAndProve compares Home B's server ID against Home A's stored credentials.serverID → mismatch → Error.identityMismatch → "Server identity mismatch" The fix The Bonjour TXT record for _companion-link._tcp includes a unique device identifier (commonly the rpBA or UniqueIdentifier field) that distinguishes hardware regardless of user-assigned name. The device ID should be derived from one of these unique TXT record fields instead of service.name. This would make the Keychain key unique per physical device rather than per display name.
kerem closed this issue 2026-03-03 16:44:54 +03:00
Author
Owner

@nickustinov commented on GitHub (Feb 9, 2026):

Fixed in 1.2.1

<!-- gh-comment-id:3871580395 --> @nickustinov commented on GitHub (Feb 9, 2026): Fixed in 1.2.1
Author
Owner

@Tledford-lab commented on GitHub (Feb 9, 2026):

Confirmed this has resolved my issue.

<!-- gh-comment-id:3871601431 --> @Tledford-lab commented on GitHub (Feb 9, 2026): Confirmed this has resolved my issue.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/itsytv-macos#10
No description provided.