1
0
mirror of https://github.com/home-assistant/core.git synced 2025-06-15 10:37:06 +00:00
core/homeassistant/components/fitbit/application_credentials.py
Allen Porter bd2fee289d
Update Fitbit integration to allow UI based configuration ()
* Cleanup fitbit sensor API parsing

* Remove API code that is not used yet

* Configuration flow for fitbit

* Code cleanup after manual review

* Streamline code for review

* Use scopes to determine which entities to enable

* Use set for entity comparisons

* Apply fitbit string pr feedback

* Improve fitbit configuration flow error handling

* Apply suggestions from code review

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

* Fix typo in more places

* Revert typing import

* Revert custom domain back to default

* Add additional config flow tests

* Add         breaks_in_ha_version to repair issues

* Update homeassistant/components/fitbit/api.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Increase test coverage for token refresh success case

* Add breaks_in_ha_version for sensor issue

* Apply suggestions from code review

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Simplify translations, issue keys, and token refresh

* Config flow test improvements

* Simplify repair issue creation on fitbit import

* Remove unused strings

---------

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2023-09-30 16:56:39 -07:00

78 lines
2.6 KiB
Python

"""application_credentials platform the fitbit integration.
See https://dev.fitbit.com/build/reference/web-api/authorization/ for additional
details on Fitbit authorization.
"""
import base64
import logging
from typing import Any, cast
from homeassistant.components.application_credentials import (
AuthImplementation,
AuthorizationServer,
ClientCredential,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_entry_oauth2_flow
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import CONF_CLIENT_ID, CONF_CLIENT_SECRET, OAUTH2_AUTHORIZE, OAUTH2_TOKEN
_LOGGER = logging.getLogger(__name__)
class FitbitOAuth2Implementation(AuthImplementation):
"""Local OAuth2 implementation for Fitbit.
This implementation is needed to send the client id and secret as a Basic
Authorization header.
"""
async def async_resolve_external_data(self, external_data: dict[str, Any]) -> dict:
"""Resolve the authorization code to tokens."""
session = async_get_clientsession(self.hass)
data = {
"grant_type": "authorization_code",
"code": external_data["code"],
"redirect_uri": external_data["state"]["redirect_uri"],
}
resp = await session.post(self.token_url, data=data, headers=self._headers)
resp.raise_for_status()
return cast(dict, await resp.json())
async def _token_request(self, data: dict) -> dict:
"""Make a token request."""
session = async_get_clientsession(self.hass)
body = {
**data,
CONF_CLIENT_ID: self.client_id,
CONF_CLIENT_SECRET: self.client_secret,
}
resp = await session.post(self.token_url, data=body, headers=self._headers)
resp.raise_for_status()
return cast(dict, await resp.json())
@property
def _headers(self) -> dict[str, str]:
"""Build necessary authorization headers."""
basic_auth = base64.b64encode(
f"{self.client_id}:{self.client_secret}".encode()
).decode()
return {"Authorization": f"Basic {basic_auth}"}
async def async_get_auth_implementation(
hass: HomeAssistant, auth_domain: str, credential: ClientCredential
) -> config_entry_oauth2_flow.AbstractOAuth2Implementation:
"""Return a custom auth implementation."""
return FitbitOAuth2Implementation(
hass,
auth_domain,
credential,
AuthorizationServer(
authorize_url=OAUTH2_AUTHORIZE,
token_url=OAUTH2_TOKEN,
),
)