picklepete / pyicloud

A Python + iCloud wrapper to access iPhone and Calendar data.
MIT License
2.56k stars 452 forks source link

Status code 421 "Misdirected Request" despite apparently successful authentication #391

Open clstaudt opened 2 years ago

clstaudt commented 2 years ago

The problem

Previously running code based on pyicloud now fails on login. A HTTP error code 421 raises PyiCloudAPIResponseException: Authentication required for Account. (421).

However, macOS and Apple's security e-mail alerts indicate that login was successful.

The login code:

def login_iCloud(user_name: str):
    """Log in to Apple iCloud"""
    password = getpass.getpass(prompt=f"iCloud password for account {user_name}: ")
    iCloud = pyicloud.PyiCloudService(user_name, password)
    if not iCloud.is_trusted_session:
        result = iCloud.validate_2fa_code(getpass.getpass(prompt="verification code: "))
    assert iCloud.is_trusted_session
    return iCloud

Environment

Traceback/Error logs

---------------------------------------------------------------------------
PyiCloudAPIResponseException              Traceback (most recent call last)
Input In [10], in <cell line: 1>()
----> 1 my_calendar = tuttle.calendar.ICloudCalendar(
      2     icloud=tuttle.cloud.login_iCloud(
      3         user_name=me.icloud_account.user_name
      4     ),
      5     name="TimeTracking",
      6 )

File ~/Documents/Work/Projects/PrototypeFund/Dev/tuttle/tuttle/calendar.py:111, in ICloudCalendar.__init__(self, icloud, name)
    109 super().__init__(name)
    110 self.icloud = icloud
--> 111 calendars = icloud.calendar.calendars()
    112 calendars_df = pandas.DataFrame(calendars)
    113 cal_to_guid = dict(
    114     (cal_name, guid)
    115     for (cal_name, guid) in zip(calendars_df["title"], calendars_df["guid"])
    116 )

File ~/miniforge3/envs/tuttle/lib/python3.10/site-packages/pyicloud/services/calendar.py:84, in CalendarService.calendars(self)
     75 params = dict(self.params)
     76 params.update(
     77     {
     78         "lang": "en-us",
   (...)
     82     }
     83 )
---> 84 req = self.session.get(self._calendars, params=params)
     85 self.response = req.json()
     86 return self.response["Collection"]

File ~/miniforge3/envs/tuttle/lib/python3.10/site-packages/requests/sessions.py:600, in Session.get(self, url, **kwargs)
    592 r"""Sends a GET request. Returns :class:`Response` object.
    593 
    594 :param url: URL for the new :class:`Request` object.
    595 :param \*\*kwargs: Optional arguments that ``request`` takes.
    596 :rtype: requests.Response
    597 """
    599 kwargs.setdefault("allow_redirects", True)
--> 600 return self.request("GET", url, **kwargs)

File ~/miniforge3/envs/tuttle/lib/python3.10/site-packages/pyicloud/base.py:131, in PyiCloudSession.request(self, method, url, **kwargs)
    129         request_logger.debug(api_error)
    130         kwargs["retried"] = True
--> 131         return self.request(method, url, **kwargs)
    133     self._raise_error(response.status_code, response.reason)
    135 if content_type not in json_mimetypes:

File ~/miniforge3/envs/tuttle/lib/python3.10/site-packages/pyicloud/base.py:133, in PyiCloudSession.request(self, method, url, **kwargs)
    130         kwargs["retried"] = True
    131         return self.request(method, url, **kwargs)
--> 133     self._raise_error(response.status_code, response.reason)
    135 if content_type not in json_mimetypes:
    136     return response

File ~/miniforge3/envs/tuttle/lib/python3.10/site-packages/pyicloud/base.py:189, in PyiCloudSession._raise_error(self, code, reason)
    187 api_error = PyiCloudAPIResponseException(reason, code)
    188 LOGGER.error(api_error)
--> 189 raise api_error

PyiCloudAPIResponseException: Authentication required for Account. (421)

Additional information

fresh2dev commented 1 year ago

I ran into this and it crippled my project. I migrated from pycloud to icloudpy and it proved to be a drop-in replacement that did not raise this issue.

https://github.com/mandarons/icloudpy

clstaudt commented 1 year ago

@fresh2dev Thank you, worked like a charm as a drop-in replacement. I guess icloudpy is the future of this project?