fix(auth): treat non-standard 403 invalid_grant as reauth instead of a silent failure - #296
Open
sslivins wants to merge 1 commit into
Open
fix(auth): treat non-standard 403 invalid_grant as reauth instead of a silent failure#296sslivins wants to merge 1 commit into
sslivins wants to merge 1 commit into
Conversation
The token-refresh handler only classified an invalidated refresh token as an auth failure when the IdP returned HTTP 400 (per RFC 6749 5.2). Generac's Auth0/Apigee IdP returns 403 for a dead refresh token, so the check fell through to a generic RuntimeError. The coordinator caught that as a plain Exception -> UpdateFailed, freezing every entity as "unavailable" and spamming "Unexpected error refreshing Generac data" with no user-facing reauth prompt. Trust the OAuth `error` field over the HTTP status: any invalid_grant payload now raises InvalidGrantError regardless of status. Additionally treat any bare 401/403 from the token endpoint as an auth failure so a rejected grant surfaces reauth instead of looping on UpdateFailed, while 5xx/network errors still fall through to RuntimeError for transient retry. Adds regression tests for the 403 invalid_grant case, a bare 403, and a transient 5xx (still RuntimeError). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
sslivins
marked this pull request as ready for review
July 29, 2026 18:25
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When a Generac refresh token is invalidated, every entity goes
unavailablewith no user-facing prompt to re-login. The log just spamsUnexpected error refreshing Generac data, and the config entry staysloaded, so there's no reauth flow and no Repairs card — the integration is silently broken until you notice the stale data yourself.Root cause: Generac returns a non-standard HTTP status
RFC 6749 §5.2 mandates that an
invalid_granterror be returned with HTTP 400. Generac's Auth0/Apigee token endpoint instead returns it as HTTP 403:The refresh handler only classified this as an auth failure on the spec-compliant status:
Because Generac sends 403, this check is skipped and execution falls through to a generic
RuntimeError. The coordinator catches that as a plainException→UpdateFailed(neverConfigEntryAuthFailed), so HA never triggers the reauth flow.Fix
Don't rely on Generac honoring the OAuth status-code convention. Trust the OAuth
errorfield over the HTTP status:invalid_grantpayload →InvalidGrantErrorregardless of HTTP status.InvalidGrantError(a rejected grant is an auth failure, not a transient outage), so we don't loop onUpdateFailedforever.RuntimeError→UpdateFailedfor transient retry.InvalidGrantErroris already mapped toConfigEntryAuthFailedin the coordinator, which starts HA's reauth flow.Tests
Adds regression tests: 403
invalid_grant, a bare 403 (no OAuth error body), and a transient 5xx (stillRuntimeError).pytest tests/test_auth.py→ 14 passed.Validation
Deployed to a live HA instance that had an already-invalidated refresh token. After restart: entry →
setup_error, a reauth flow starts (step: reauth_confirm), a Repairs card appears (config_entry_reauth_generac_…), and the log now readsGenerac auth rejected, requesting reauthinstead ofUnexpected error refreshing Generac data.Complementary to #286 (which fixed the entry not reloading after a successful reauth); this fixes the reauth prompt not appearing in the first place.
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com