From d4df85e155715b46dfd0565dbbe73dca48ca1b80 Mon Sep 17 00:00:00 2001 From: juliangall <11220541+juliangall@users.noreply.github.com> Date: Wed, 18 Feb 2026 07:30:10 +0000 Subject: [PATCH] Fix device_login failing when login returns AuthenticationResult directly When hiveRefreshTokens falls back to deviceLogin due to an expired/invalid refresh token, device_login calls login() which can return an AuthenticationResult directly (no device challenge) when device tracking is not enforced by the Cognito user pool. Previously this case fell through to the else branch and raised HiveInvalidDeviceAuthentication, preventing the integration from loading. Also handle SMS_MFA challenge in device_login by raising HiveReauthRequired so Home Assistant can trigger a proper re-auth flow for accounts with 2FA enabled. Co-Authored-By: Claude Sonnet 4.6 --- src/api/hive_auth.py | 11 +++++++++++ src/api/hive_auth_async.py | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/api/hive_auth.py b/src/api/hive_auth.py index b27788c..9ce7d75 100644 --- a/src/api/hive_auth.py +++ b/src/api/hive_auth.py @@ -18,6 +18,7 @@ HiveInvalidDeviceAuthentication, HiveInvalidPassword, HiveInvalidUsername, + HiveReauthRequired, ) from .hive_api import HiveApi @@ -383,6 +384,12 @@ def login(self): def device_login(self): """Perform device login instead.""" login_result = self.login() + + if "AuthenticationResult" in login_result: + # Login succeeded without a device challenge (e.g. device tracking + # not enforced). Tokens are already valid, return them directly. + return login_result + auth_params = self.get_auth_params() auth_params["DEVICE_KEY"] = self.device_key @@ -405,6 +412,10 @@ def device_login(self): except botocore.exceptions.EndpointConnectionError as err: if err.__class__.__name__ == "EndpointConnectionError": raise HiveApiError from err + elif login_result.get("ChallengeName") == self.SMS_MFA_CHALLENGE: + # Account has 2FA enabled and device is not remembered by Cognito. + # Automatic re-authentication is not possible without user interaction. + raise HiveReauthRequired else: raise HiveInvalidDeviceAuthentication diff --git a/src/api/hive_auth_async.py b/src/api/hive_auth_async.py index a1e03b8..5c487b6 100644 --- a/src/api/hive_auth_async.py +++ b/src/api/hive_auth_async.py @@ -22,6 +22,7 @@ HiveInvalidDeviceAuthentication, HiveInvalidPassword, HiveInvalidUsername, + HiveReauthRequired, ) from .hive_api import HiveApi @@ -407,6 +408,12 @@ async def login(self): async def device_login(self): """Perform device login instead.""" login_result = await self.login() + + if "AuthenticationResult" in login_result: + # Login succeeded without a device challenge (e.g. device tracking + # not enforced). Tokens are already valid, return them directly. + return login_result + auth_params = await self.get_auth_params() auth_params["DEVICE_KEY"] = self.device_key @@ -437,6 +444,10 @@ async def device_login(self): except botocore.exceptions.EndpointConnectionError as err: if err.__class__.__name__ == "EndpointConnectionError": raise HiveApiError from err + elif login_result.get("ChallengeName") == self.SMS_MFA_CHALLENGE: + # Account has 2FA enabled and device is not remembered by Cognito. + # Automatic re-authentication is not possible without user interaction. + raise HiveReauthRequired else: raise HiveInvalidDeviceAuthentication