Skip to content

fix: make V02 authentication failures recoverable - #124

Open
hugo-brito wants to merge 4 commits into
cdpuk:mainfrom
hugo-brito:fix/v02-surface-failures-and-command-verify
Open

fix: make V02 authentication failures recoverable#124
hugo-brito wants to merge 4 commits into
cdpuk:mainfrom
hugo-brito:fix/v02-surface-failures-and-command-verify

Conversation

@hugo-brito

@hugo-brito hugo-brito commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Problem

V02 authentication failures could leave the integration unavailable or serving stale cached state until a manual reload:

  • A startup authentication timeout escaped as a generic exception, putting the config entry in setup_error without automatic retry.
  • Runtime token rejection was swallowed by per-device polling, so the coordinator could continue reporting stale data as available.
  • Refreshed REST tokens were not propagated consistently to active WebSockets.
  • The integration had no V02 reauthentication flow.

Observed incident: AwsIotApi.authenticate() timed out after 10 seconds during Home Assistant startup, producing TimeoutError and Error setting up entry Bestway Spa (V02 - EU) with no retry.

Changes

  • Classify transient authentication connectivity failures as AwsIotConnectionError and map them to ConfigEntryNotReady.
  • Keep definitive 401/403 or missing-token responses as AwsIotAuthException / ConfigEntryAuthFailed.
  • Increase the V02 authentication timeout to 20 seconds.
  • Reauthenticate once when any device poll reports token rejection, including partial multi-device failures.
  • Raise UpdateFailed when no device refreshes, preventing stale state from remaining available.
  • Propagate runtime-refreshed tokens in memory to the API and every active V02 WebSocket without updating config data, which avoids triggering the entry reload listener. Startup still obtains and stores a fresh token before that listener is registered.
  • Remove the coordinator's conflicting 10-second aggregate timeout; individual HTTP calls remain bounded by their backend timeouts, allowing multi-device reauth and repoll cycles to complete.
  • Add a passwordless V02 reauth flow using the stored visitor_id.
  • Check auth status before parsing response bodies so non-JSON 401/403 responses are classified correctly.

Scope

This update intentionally removes the unrelated command-convergence experiment previously present on this PR branch. That work had unresolved false-positive behavior for rapid commands and should be handled separately.

Validation

  • Full Linux/Podman suite: 97 passed.
  • Ruff 0.15.10 check and formatting pass.
  • Mypy passes for all 19 integration source files.
  • Regression coverage includes startup timeout/rejection, runtime reauth success/failure, partial-device auth failure, total poll failure, no reload on runtime token refresh, active WebSocket token propagation, reauth flow, and non-JSON auth responses.

Based on current upstream main (570c817).

@hugo-brito
hugo-brito force-pushed the fix/v02-surface-failures-and-command-verify branch from 2684936 to d2b972f Compare June 30, 2026 20:55
@hugo-brito

Copy link
Copy Markdown
Contributor Author

@cdpuk please have a look ;)

Comment thread custom_components/bestway/aws_iot/api.py Outdated
Comment thread custom_components/bestway/aws_iot/api.py Outdated
Comment thread custom_components/bestway/aws_iot/api.py Outdated
Comment thread custom_components/bestway/coordinator.py Outdated
Comment thread custom_components/bestway/aws_iot/api.py Outdated
Comment thread custom_components/bestway/const.py Outdated
hugo-brito and others added 3 commits August 5, 2026 21:44
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@hugo-brito
hugo-brito force-pushed the fix/v02-surface-failures-and-command-verify branch from 52934d2 to e6222fc Compare August 5, 2026 20:18
@hugo-brito hugo-brito changed the title fix: surface failed V02 polls and re-auth instead of serving stale data fix: make V02 authentication failures recoverable Aug 5, 2026
@hugo-brito

Copy link
Copy Markdown
Contributor Author

Reworked this PR on fresh main and replaced the previous mixed-scope history with the auth-only implementation requested in the review.

Addressed the review feedback:

  • Reauthenticate on any per-device auth failure, including when another device refreshed successfully (refreshed == 0 is no longer required); added a partial multi-device regression test.
  • Removed the command-convergence experiment entirely, including Fix B, local documentation/Tier C references, custom events, and the rapid-command false-positive behavior.
  • Kept this PR focused on authentication resilience and stale-state handling.
  • Added startup timeout retry classification, typed transient/auth failures, first-refresh and WebSocket token propagation, passwordless V02 reauth, and non-JSON auth-response handling.

The branch is now based on current upstream main (570c817). All upstream checks pass (Validate, pre-commit, and tests), plus 36 targeted Podman tests passed locally. Ready for re-review.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@hugo-brito

Copy link
Copy Markdown
Contributor Author

Final merge-readiness pass completed after the auth-only rewrite.

Two additional lifecycle issues found during independent red-team review are now fixed:

  • Runtime token refresh no longer writes config-entry data, so it does not trigger the generic update listener and race a full unload/reload against the in-flight coordinator update. Tokens are propagated in memory to the API, the WebSocket seed token, and every active V02 WebSocket; startup still persists a fresh token safely before the listener is registered.
  • Removed the coordinator's conflicting 10-second aggregate timeout. Each HTTP call remains bounded by its backend timeout, while multi-device authenticate-and-repoll recovery can now finish.

Added regression coverage for both the no-reload behavior and active-WebSocket token propagation.

Final validation:

  • Full Linux suite: 97 passed
  • Upstream Validate: passed
  • Upstream pre-commit: passed
  • Upstream tests: passed
  • Ruff 0.15.10 check/format: passed
  • Mypy: passed (19 source files)

Independent final review found no remaining high-confidence merge blockers. The prior owner feedback is fully addressed; ready for re-review.

@hugo-brito

Copy link
Copy Markdown
Contributor Author

@cdpuk please have a look :)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants