fix: trigger 2FA push notification on iOS 26.4+ (resolves the auth stall in mandarons/icloud-docker#426)#138
Merged
Conversation
Apple's auth flow changed around iOS 26 / early 2026. The 2FA prompt no longer arrives on trusted devices unless the client first sends a PUT to /verify/trusteddevice/securitycode (no body) to explicitly request the push. Without this, requires_2fa returns True but the user sees no code on any device — auth stalls. Adds a new public method `ICloudPyService.trigger_2fa_push_notification()` that does the PUT. Callers should invoke it before prompting the user for the code. Failure is non-fatal (returns False) — a code may still arrive via SMS or another path. Wired into the bundled `icloudpy` CLI (cmdline.py) so it works out of the box. Other callers (mandarons/icloud-docker, etc.) just need to add a single `api.trigger_2fa_push_notification()` call before their existing code prompt. Ported from icloud_photos_downloader PR #1335 (which solved the same issue in their fork of pyicloud). The fix has been validated by the boredazfcuk/docker-icloudpd community since 2026-05-04 and is the known working solution. Tests: - New trigger_2fa_push_notification test (HTTP 204 success path) - New scnt + session_id headers test (forwarding correctness) - New API exception non-fatal test (graceful failure) - Existing 212 tests still pass (only pre-existing test_storage ordering issue remains, unrelated)
…re test Addresses two code-review items on the iOS 26.4 fix: 1. trigger_2fa_push_notification() previously caught only ICloudPyAPIResponseException. Network/transport errors (ConnectionError, Timeout, SSLError) would propagate to callers despite the docstring promising non-fatal behavior. Broadened the catch to `except Exception` so all transient failures return False as advertised. The push is best-effort anyway — a code may still arrive via SMS or other paths. 2. Added test_trigger_2fa_push_notification_network_failure_is_non_fatal exercising three real requests exceptions (ConnectionError, Timeout, SSLError) to enforce the broadened contract. Also dropped two duplicate `from unittest.mock import patch` re-imports inside test methods — `patch` is already imported at module level. 213 passed + 1 pre-existing unrelated failure (test_storage).
CRITICAL-1 from pre-submission review. The earlier review-fix commit (broaden exception catch) accidentally ADDED a second copy of the method instead of REPLACING the original. Python silently took the second (broader-catch) definition; the first was dead code that would produce a SyntaxWarning in Python 3.12+ and would have been the first thing a maintainer flagged on the upstream PR. Removes the first (narrow-catch) definition. The remaining (broad-catch) version is the one the tests already exercise and the one wired into cmdline.py.
CI runs `ruff check && pytest`. The recent review-driven commits introduced two trailing-comma issues: - icloudpy/cmdline.py:241 — multi-line print() inside the iOS 26.4 push-trigger fallback. - tests/test_auth.py:568 — multi-line call in TestErrorCodeHandling. Auto-fixed with `ruff check --fix`. No semantic change. Verified on a python:3.10 docker that mirrors mandarons' CI: 214 passed, 80.60% coverage (above the 78% gate). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds an explicit 2FA “push trigger” step required by Apple’s updated authentication flow (iOS 26.4+), exposing it as a new ICloudPyService API and invoking it in the bundled CLI before prompting for the 6‑digit code.
Changes:
- Added
ICloudPyService.trigger_2fa_push_notification()to initiate delivery of a 2FA code to trusted devices viaPUT /verify/trusteddevice/securitycode. - Wired the new method into
icloudpy’s CLI 2FA flow so users receive a prompt after the push is triggered. - Extended the test suite and mocks to cover the new flow and non-fatal error handling.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
icloudpy/base.py |
Adds the new trigger_2fa_push_notification() method to the core service API. |
icloudpy/cmdline.py |
Calls the new trigger method when requires_2fa is true, before prompting for the code. |
tests/__init__.py |
Updates the session mock to return a successful response for the new PUT endpoint. |
tests/test_auth.py |
Adds unit tests validating the new method behavior (success, header forwarding, non-fatal failures). |
…e and return False Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
mandarons
approved these changes
May 30, 2026
|
@mandarons tried the latest version with no success, I still get no popup on any trusted device. Any idea? |
Contributor
Author
|
Looks like I hadn't wired this up right for re-auth only initial auth. I've fixed and tested this for re-auth and added a telegram flow through the existing integration. This PR adds the icloudpy support and the following PR uses it: mandarons/icloud-docker#470 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Restores 2FA on iOS 26.4+ trusted devices.
Since iOS 26.4 (Feb 2026),
validate_2fa_code()is unreachable in practicebecause the 6-digit code never arrives on any trusted device — Apple changed
the flow to require an explicit
PUT /verify/trusteddevice/securitycode(no body) to initiate code delivery. Without it, callers see
"Please enter validation code" and wait forever.
This PR adds
ICloudPyService.trigger_2fa_push_notification()— the explicitPUT — and wires it into the bundled
icloudpyCLI so it works out of thebox. The bundled
cmdline.pycalls it right afterrequires_2fareturnsTrue and before prompting the user for the code.
Other library consumers (mandarons/icloud-docker, etc.) need only add a
single
api.trigger_2fa_push_notification()call before their ownprompt-for-code logic to inherit the fix.
Refs: mandarons/icloud-docker#426
Validation
tests/test_auth.py:test_trigger_2fa_push_notification_success(happy path via mock)test_trigger_2fa_push_notification_includes_session_headers(scnt + session_id forwarding)test_trigger_2fa_push_notification_api_failure_is_non_fatal(ICloudPyAPIResponseException → False)test_trigger_2fa_push_notification_network_failure_is_non_fatal(ConnectionError / Timeout / SSLError → False)test_storageordering issueremains, unrelated to this change.
push notification arrived, code accepted, Photos + Drive services reachable.
Approach
Ported from icloud-photos-downloader/icloud_photos_downloader#1335. That fix
has been validated in the
boredazfcuk/docker-icloudpdcommunity since2026-05-04 and is the known-working solution. This PR adapts the same
approach to icloudpy's smaller, simpler API surface.
Notes
ICloudPyAPIResponseExceptionAND network-level exceptions like
Timeout/ConnectionError/SSLError).A code may still arrive via SMS or another path, and callers can fall
through to the
validate_2fa_codecall regardless.pyicloud_ipd/sms.pychanges)is not ported here — icloudpy doesn't have an equivalent SMS parser. Its
2SA flow uses
validate_verification_codevia/listDevices, which is aseparate code path that hasn't been affected by the iOS 26.4 change.