Skip to content

feat(mobile): surface pairing-auth failures on desktop and mobile - #9782

Merged
brennanb2025 merged 6 commits into
mainfrom
brennanb2025/mobile-pair-auth-surface
Jul 22, 2026
Merged

brennanb2025 merged 6 commits into
mainfrom
brennanb2025/mobile-pair-auth-surface

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor

Part of the mobile version-skew incident response: desktops that hit the pre-v1.4.106 pairing-path bug lost their E2EE keypair / device registry, so previously-paired phones fail auth forever with 4001 Unauthorized — and both ends stay silent (desktop drops the connection, phone loops the generic reconnect).

Desktop

  • New UnpairedDeviceAuthThrottle (src/main/runtime/rpc/unpaired-device-auth-throttle.ts): 3 unpaired direct-transport auth failures within 60s fire a single notification per runtime session. Relay attempts are excluded because they are authorized upstream.
  • Missing device tokens and auth frames encrypted to a stale desktop key both use the same bounded path. A wrong key is rejected immediately as 4001 instead of waiting for a generic handshake timeout; post-auth decrypt failures retain the existing five-strike protection.
  • The renderer shows a sonner warning toast with an Open Mobile Settings action that deep-links to Settings → Mobile for re-pairing. A one-shot consume handshake preserves the notification across runtime/renderer startup races and React Strict Mode remounts.
  • The web preload stays a no-op. Headless orca serve retains at most one pending boolean and performs no polling or renderer work.

Mobile

  • A bare 4001 close now counts against the existing AUTH_RETRY_BUDGET in rpc-client.ts instead of feeding the endless generic reconnect loop. This matters when the encrypted e2ee_error is lost or undecryptable and the close code is the only surviving auth-failure signal. Three strikes (shared budget with decrypted e2ee_error rejections) latch auth-failed, which the host-detail screen already surfaces with Retry / Re-pair / Remove actions.
  • The auth-failed verdict label is now “Pairing invalid — re-pair with your desktop” (host card / status dot) and “Pairing invalid” in session route labels, instead of a generic “Auth failed”.

Tests

  • Throttle: threshold, once-per-session, bounded window pruning (unpaired-device-auth-throttle.test.ts).
  • Desktop auth: unknown token and stale-key auth both report direct-transport metadata and close 4001; authenticated-channel decrypt failure tolerance remains covered.
  • Renderer delivery: pre-mount retention, concurrent live/mount dedupe, old-preload fallback, and Strict Mode cleanup.
  • Mobile close-code mapping: 4001 latches after budget, transient 4001 recovers, budget is shared with e2ee_error, and non-4001 keeps generic retry.
  • Full mobile suite: 2,175 passed, 2 skipped. Focused desktop tests, node/web/mobile typechecks, changed-file lint, mobile lint/format, max-lines ratchet, locale parity, and reliability gates pass.

Follow-up

  • Relay/v2 path latches auth-failed on the first decrypted e2ee_error (no 3-retry budget), so behavior differs between direct and relay transports — worth unifying.

Note: two pre-existing lint failures on the base branch (skill-freshness-group.tsx switch-exhaustiveness, AI Vault localization coverage) are unrelated to this change.

…f silent 4001 loops

Desktop: when a phone repeatedly fails direct-transport E2EE auth with a
token missing from the device registry (pre-v1.4.106 pairing-path bug left
desktops that regenerated their registry rejecting paired phones forever),
throttle to one notification per session and show an actionable toast
pointing at Settings -> Mobile to re-pair.

Mobile: map a bare 4001 close onto the existing auth retry budget (the
encrypted e2ee_error is undecryptable when the desktop keypair changed, so
the close code is the only surviving signal) instead of looping the generic
reconnect forever, and make the auth-failed verdict say 'Pairing invalid -
re-pair with your desktop' instead of a bare 'Auth failed'.
@coderabbitai

coderabbitai Bot commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: eac13b26-6b9a-495d-b639-16dcb36cdba7

📥 Commits

Reviewing files that changed from the base of the PR and between ae2dc1d and 544a1a5.

📒 Files selected for processing (4)
  • mobile/src/transport/rpc-client-unauthorized-close.test.ts
  • mobile/src/transport/rpc-client.ts
  • src/main/runtime/runtime-rpc.ts
  • src/renderer/src/hooks/useIpcEvents.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/renderer/src/hooks/useIpcEvents.ts
  • mobile/src/transport/rpc-client-unauthorized-close.test.ts
  • src/main/runtime/runtime-rpc.ts
  • mobile/src/transport/rpc-client.ts

📝 Walkthrough

Walkthrough

The PR adds unauthorized E2EE authentication handling for stale or invalid pairing credentials, including WebSocket close code 4001 and mobile auth-failure state labeling. Direct transport failures are throttled before notification. Main-process IPC and preload APIs support pending and live failure notifications. Renderer code consumes these notifications and displays localized re-pairing guidance with a Mobile Settings action.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is detailed, but it does not follow the required template and omits Screenshots, AI Review Report, Security Audit, and Notes sections. Reformat the PR description to the required headings and add a Screenshots/no visual change note, AI review report, security audit, and notes.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: surfacing pairing-auth failures on desktop and mobile.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@AmethystLiang AmethystLiang added the orca-remote-server Remote Orca Server / orca serve / paired remote runtime label Jul 22, 2026
@brennanb2025

Copy link
Copy Markdown
Contributor Author

QA screenshots

Tested the PR branch on the isolated Electron app and an iPhone 17 Pro simulator.

Scenario: a saved mobile host with stale pairing credentials connected to the current desktop. Three real WebSocket 4001 Unauthorized responses exhausted the retry budget and surfaced the recovery state.

Desktop authentication warning

Desktop authentication warning

The Open Mobile Settings action navigated to Settings → Mobile:

Desktop Mobile settings

Mobile authentication failure

Mobile host overview

The host detail exposes the complete recovery guidance and Retry, Re-pair, and Remove actions:

Mobile pairing-invalid detail

Platform scope: iOS was captured; Android was not separately exercised. No repository files were changed for this QA pass.

@brennanb2025
brennanb2025 merged commit d6c9fcd into main Jul 22, 2026
5 checks passed
enrick-dev pushed a commit to enrick-dev/orca that referenced this pull request Oct 15, 2026
…ablyai#9782)

* feat(mobile-pairing): surface unpaired-device auth failures instead of silent 4001 loops

Desktop: when a phone repeatedly fails direct-transport E2EE auth with a
token missing from the device registry (pre-v1.4.106 pairing-path bug left
desktops that regenerated their registry rejecting paired phones forever),
throttle to one notification per session and show an actionable toast
pointing at Settings -> Mobile to re-pair.

Mobile: map a bare 4001 close onto the existing auth retry budget (the
encrypted e2ee_error is undecryptable when the desktop keypair changed, so
the close code is the only surviving signal) instead of looping the generic
reconnect forever, and make the auth-failed verdict say 'Pairing invalid -
re-pair with your desktop' instead of a bare 'Auth failed'.

* fix(mobile-pairing): handle stale keys and startup notification races

* fix(mobile-pairing): isolate auth notification failures

* fix(mobile-pairing): keep recovery alert actionable
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

orca-remote-server Remote Orca Server / orca serve / paired remote runtime

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants