From 1a878b40246fa1580f7e8b6082d132cc8158cefb Mon Sep 17 00:00:00 2001 From: Nenad Bogojevic Date: Fri, 28 Jan 2022 17:48:16 +0100 Subject: [PATCH] Use new withings oauth2 refresh token endpoint (#65134) --- homeassistant/components/withings/__init__.py | 4 +- homeassistant/components/withings/common.py | 43 +++++++++++++++++++ homeassistant/components/withings/sensor.py | 1 - tests/components/withings/common.py | 14 +++--- tests/components/withings/test_config_flow.py | 14 +++--- 5 files changed, 61 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/withings/__init__.py b/homeassistant/components/withings/__init__.py index 800f8b654bb..701694e40e9 100644 --- a/homeassistant/components/withings/__init__.py +++ b/homeassistant/components/withings/__init__.py @@ -9,7 +9,7 @@ import asyncio from aiohttp.web import Request, Response import voluptuous as vol -from withings_api import WithingsAuth +from withings_api import AbstractWithingsApi, WithingsAuth from withings_api.common import NotifyAppli from homeassistant.components import webhook @@ -84,7 +84,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: conf[CONF_CLIENT_ID], conf[CONF_CLIENT_SECRET], f"{WithingsAuth.URL}/oauth2_user/authorize2", - f"{WithingsAuth.URL}/oauth2/token", + f"{AbstractWithingsApi.URL}/v2/oauth2", ), ) diff --git a/homeassistant/components/withings/common.py b/homeassistant/components/withings/common.py index 8da67a0b77a..56f7f7cdf91 100644 --- a/homeassistant/components/withings/common.py +++ b/homeassistant/components/withings/common.py @@ -1111,3 +1111,46 @@ class WithingsLocalOAuth2Implementation(LocalOAuth2Implementation): """Return the redirect uri.""" url = get_url(self.hass, allow_internal=False, prefer_cloud=True) return f"{url}{AUTH_CALLBACK_PATH}" + + async def _token_request(self, data: dict) -> dict: + """Make a token request and adapt Withings API reply.""" + new_token = await super()._token_request(data) + # Withings API returns habitual token data under json key "body": + # { + # "status": [{integer} Withings API response status], + # "body": { + # "access_token": [{string} Your new access_token], + # "expires_in": [{integer} Access token expiry delay in seconds], + # "token_type": [{string] HTTP Authorization Header format: Bearer], + # "scope": [{string} Scopes the user accepted], + # "refresh_token": [{string} Your new refresh_token], + # "userid": [{string} The Withings ID of the user] + # } + # } + # so we copy that to token root. + if body := new_token.pop("body", None): + new_token.update(body) + return new_token + + async def async_resolve_external_data(self, external_data: Any) -> dict: + """Resolve the authorization code to tokens.""" + return await self._token_request( + { + "action": "requesttoken", + "grant_type": "authorization_code", + "code": external_data["code"], + "redirect_uri": external_data["state"]["redirect_uri"], + } + ) + + async def _async_refresh_token(self, token: dict) -> dict: + """Refresh tokens.""" + new_token = await self._token_request( + { + "action": "requesttoken", + "grant_type": "refresh_token", + "client_id": self.client_id, + "refresh_token": token["refresh_token"], + } + ) + return {**token, **new_token} diff --git a/homeassistant/components/withings/sensor.py b/homeassistant/components/withings/sensor.py index 0ca40d28440..f8753739519 100644 --- a/homeassistant/components/withings/sensor.py +++ b/homeassistant/components/withings/sensor.py @@ -15,7 +15,6 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up the sensor config entry.""" - entities = await async_create_entities( hass, entry, diff --git a/tests/components/withings/common.py b/tests/components/withings/common.py index 71eb350410b..b90a004ed0b 100644 --- a/tests/components/withings/common.py +++ b/tests/components/withings/common.py @@ -216,13 +216,15 @@ class ComponentFactory: self._aioclient_mock.clear_requests() self._aioclient_mock.post( - "https://account.withings.com/oauth2/token", + "https://wbsapi.withings.net/v2/oauth2", json={ - "refresh_token": "mock-refresh-token", - "access_token": "mock-access-token", - "type": "Bearer", - "expires_in": 60, - "userid": profile_config.user_id, + "body": { + "refresh_token": "mock-refresh-token", + "access_token": "mock-access-token", + "type": "Bearer", + "expires_in": 60, + "userid": profile_config.user_id, + }, }, ) diff --git a/tests/components/withings/test_config_flow.py b/tests/components/withings/test_config_flow.py index 210d1f669e9..2643ac18c24 100644 --- a/tests/components/withings/test_config_flow.py +++ b/tests/components/withings/test_config_flow.py @@ -90,13 +90,15 @@ async def test_config_reauth_profile( aioclient_mock.clear_requests() aioclient_mock.post( - "https://account.withings.com/oauth2/token", + "https://wbsapi.withings.net/v2/oauth2", json={ - "refresh_token": "mock-refresh-token", - "access_token": "mock-access-token", - "type": "Bearer", - "expires_in": 60, - "userid": "0", + "body": { + "refresh_token": "mock-refresh-token", + "access_token": "mock-access-token", + "type": "Bearer", + "expires_in": 60, + "userid": "0", + }, }, )