Skip to content

Handle 2FA-required errors separately from password-reset errors#169005

Open
TeroPihlaja wants to merge 11 commits intohome-assistant:devfrom
TeroPihlaja:fix/icloud-2fa-aware-setup-errors
Open

Handle 2FA-required errors separately from password-reset errors#169005
TeroPihlaja wants to merge 11 commits intohome-assistant:devfrom
TeroPihlaja:fix/icloud-2fa-aware-setup-errors

Conversation

@TeroPihlaja
Copy link
Copy Markdown

@TeroPihlaja TeroPihlaja commented Apr 23, 2026

Problem

When iCloud login fails, the integration treated all failures the same way — logging a generic "Your password is no longer working" error regardless of the actual cause. This was confusing for users who only needed to verify a 2FA code (which is a temporary config state) versus those with truly invalid credentials.

Additionally, PyiCloudAuthRequiredException was not caught, causing the setup flow to crash if FMIP service required re-authentication even after the main login succeeded.

Changes

account.py:

  • Add PyiCloudAuthRequiredException import
  • Modify PyiCloudFailedLoginException handler to check api.requires_2fa first:
    • If True: log WARNING with user-friendly message directing them to enter their verification code
    • If False: log ERROR with message to reset password (original behavior)
  • Add new except PyiCloudAuthRequiredException: block with the same 2FA-aware logging logic

Result: Users now see actionable, contextual error messages instead of generic password-reset prompts when they only need to verify a code.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Checklist

  • The code change is tested and works locally
  • Local tests pass with python -m pytest tests/components/icloud/

Co-authored with Claude Sonnet 4.6

…Cloud setup

When iCloud login fails, distinguish between two scenarios:

1. **Password needs resetting** — OAuth fails, credentials are invalid.
   Log ERROR directing user to re-enter password.

2. **2FA verification code needed** — Login succeeded but FMIP service
   requires additional MFA (common when the Apple account has MFA
   enabled but no verification code was cached yet).
   Log WARNING with gentler language directing user to enter verification
   code via the UI configuration menu.

Added handler for `PyiCloudAuthRequiredException` which is raised when
the FMIP service specifically requires re-authentication even after the
main iCloud login succeeded. Apply the same 2FA-aware logging here.

This provides clearer, more actionable error messages and prevents users
from resetting their password when they only need to verify a code.
@TeroPihlaja TeroPihlaja requested a review from Quentame as a code owner April 23, 2026 22:09
Copilot AI review requested due to automatic review settings April 23, 2026 22:09
@home-assistant
Copy link
Copy Markdown
Contributor

Hey there @Quentame, @nzapponi, mind taking a look at this pull request as it has been labeled with an integration (icloud) you are listed as a code owner for? Thanks!

Code owner commands

Code owners of icloud can trigger bot actions by commenting:

  • @home-assistant close Closes the pull request.
  • @home-assistant mark-draft Mark the pull request as draft.
  • @home-assistant ready-for-review Remove the draft status from the pull request.
  • @home-assistant rename Awesome new title Renames the pull request.
  • @home-assistant reopen Reopen the pull request.
  • @home-assistant unassign icloud Removes the current integration label and assignees on the pull request, add the integration domain after the command.
  • @home-assistant update-branch Update the pull request branch with the base branch.
  • @home-assistant add-label needs-more-information Add a label (needs-more-information, problem in dependency, problem in custom component, problem in config, problem in device, feature-request) to the pull request.
  • @home-assistant remove-label needs-more-information Remove a label (needs-more-information, problem in dependency, problem in custom component, problem in config, problem in device, feature-request) on the pull request.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves the iCloud integration’s setup error handling so 2FA-required states are distinguished from invalid-credential states, and prevents crashes when iCloud requires re-authentication after initial login.

Changes:

  • Add handling for PyiCloudAuthRequiredException during account setup.
  • Differentiate logging between “2FA required” vs “password invalid / re-login required” scenarios.
  • Adjust the PyiCloudFailedLoginException path to emit a 2FA-specific warning when applicable.

Comment thread homeassistant/components/icloud/account.py Outdated
Comment thread homeassistant/components/icloud/account.py Outdated
Comment thread homeassistant/components/icloud/account.py
@TeroPihlaja
Copy link
Copy Markdown
Author

Could a maintainer please add the bugfix label? The CI required-labels check requires it.

pyicloud is a third-party package and must be imported before the
homeassistant first-party imports. Also removes the unused
PyiCloudFailedLoginException import.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 23, 2026 23:16
TeroPihlaja and others added 3 commits April 24, 2026 02:23
ruff isort places from-imports before bare imports alphabetically
within the same section. pyicloud (p-y-i) sorts before pytest (p-y-t).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The constructor signature is __init__(self, response), not a message
string. Pass None since the test only verifies the exception is caught,
not the response contents.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The constructor is __init__(self, apple_id: str, response: Response).
Pass both required arguments to instantiate correctly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

Comment thread homeassistant/components/icloud/account.py
Comment thread tests/components/icloud/test_account.py
Comment thread homeassistant/components/icloud/account.py Outdated
- Catch PyiCloudAuthRequiredException also when accessing api.devices.user_info,
  not only during PyiCloudService construction — prevents an unhandled exception
  crash if FMIP re-auth is required after the initial login succeeded
- Add test for this new code path
- Fix inline comment on PyiCloudFailedLoginException handler to reflect that it
  can indicate 2FA requirement, not just invalid credentials

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

Comment thread tests/components/icloud/test_account.py
Comment thread homeassistant/components/icloud/account.py Outdated
Comment thread homeassistant/components/icloud/account.py Outdated
…es handler

- Extract shared PyiCloudAuthRequiredException logging/reauth logic into
  _handle_auth_required(requires_2fa) to prevent the two handlers diverging
- Third handler (devices.user_info) now checks requires_2fa before logging,
  so it correctly logs warning vs error like the other handlers do
- Add _LOGGER assertions to test_setup_auth_required_exception_from_devices
  to verify error is logged (not warning) when requires_2fa is False

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread tests/components/icloud/test_account.py Outdated
…gicMock type

type(MagicMock()).user_info = PropertyMock(...) mutates the global MagicMock
class and leaks into other tests. Replace with a scoped inner class whose
user_info property raises PyiCloudAuthRequiredException directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread homeassistant/components/icloud/account.py
The existing tests only exercised the error branch (requires_2fa=False).
Testing the helper directly avoids the setup() complexity where requires_2fa=True
in the first try block would trigger PyiCloudFailedLoginException instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment thread homeassistant/components/icloud/account.py Outdated
Comment thread homeassistant/components/icloud/account.py Outdated
- Set self.api = None before the try block so exception handlers never
  see a stale API instance if PyiCloudService() raises mid-construction
- Route the requires_2fa=True branch of PyiCloudFailedLoginException
  through _handle_auth_required(True), eliminating the duplicate 2FA
  warning message; only the unique bad-password error stays inline

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@TeroPihlaja TeroPihlaja marked this pull request as ready for review April 28, 2026 14:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants