Skip to content
This repository was archived by the owner on Nov 26, 2024. It is now read-only.
This repository was archived by the owner on Nov 26, 2024. It is now read-only.

Refreshing token doesn't work #14

Description

@ctmbl

The HaApiV5 which inherit from ApiV5Client which itself is composed of the OAuth2Api is supposed to handled the token refreshing itself.
In ApiV5Client.call:

def call(
        self,
        sub_path: str,
        params: dict = None,
        method: str = "GET",
        data: dict = None,
        json: dict = None,
        headers: dict = None,
        include_auth: bool = True,
    ) -> Response:
        """Manage all api calls. It also handle re-authentication if necessary."""
        self.log.debug(f"Call : {method} : {sub_path}")
        url, headers, data, json, params = self.prepare_request(
            sub_path, headers, data, json, params, include_auth
        )

        try:
            result = self.execute_request(url, method, headers, data, json, params)
            return result
        except ApiV5Unauthorized:
            self.log.warning("401 Unauthorized response to API request.")
            if self.oauth.access_token:
                self.log.info("Refreshing access token")
                self.oauth.refresh_tokens()
            else:
                self.log.info("Get access token")
                self.oauth.get_token()
            return self.call(
                sub_path, params=params, method=method, data=data, headers=headers
            )

A call is tryed and if an Exception is raised it refresh/get the token it if it exists/is None.

However it returns itself, recursively, after refreshing, but with the old headers which embeds the old token, since the line

...
        url, headers, data, json, params = self.prepare_request(
            sub_path, headers, data, json, params, include_auth
        )
...

because prepare_request returns the token in the headers object.
Now in prepare_request the new token is gotten in

        self.auth = (
            {"Authorization": f"Bearer {self.oauth.access_token}"}
            if include_auth
            else {}
        )

but then overwritten by the old one stored in headers

        all_headers = {**self.header(), **self.auth, **headers}

thus the old token is used the header request and it fails its task of handling token refresh

This diff should fix the problem:

        self.log.debug(f"Call : {method} : {sub_path}")
-        url, headers, data, json, params = self.prepare_request(
+        url, all_headers, data, json, params = self.prepare_request(
            sub_path, headers, data, json, params, include_auth
        )

        try:
-           result = self.execute_request(url, method, headers, data, json, params)
+           result = self.execute_request(url, method, all_headers, data, json, params)
            return result
        except ApiV5Unauthorized:
            self.log.warning("401 Unauthorized response to API request.")
            if self.oauth.access_token:
                self.log.info("Refreshing access token")
                self.oauth.refresh_tokens()
            else:
                self.log.info("Get access token")
                self.oauth.get_token()
            return self.call(
                sub_path, params=params, method=method, data=data, headers=headers
            )

because it doesn't overwrite the header var and then when return recursively it returns the user-defined headers, not embedding the old token.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions