Skip to content

Recover from a 401 by refreshing the token and retrying (no re-login)#711

Open
magne4000 wants to merge 1 commit into
anxdpanic:masterfrom
magne4000:feature/oauth-401-recovery
Open

Recover from a 401 by refreshing the token and retrying (no re-login)#711
magne4000 wants to merge 1 commit into
anxdpanic:masterfrom
magne4000:feature/oauth-401-recovery

Conversation

@magne4000

Copy link
Copy Markdown

Summary

Makes a mid-session 401 from the Helix API self-heal via the stored refresh token instead of forcing a re-login, and skips a doomed refresh while offline.

Motivation

Today a 401 shows a hard "OAuth token is required" dialog and exits, even when a valid refresh token is still stored — which happens routinely when the short-lived access token lapses (Kodi or the network only just came up after a reboot or an overnight gap). The proactive refresh in Twitch.__init__ doesn't cover a token that expires or is rejected mid-session.

Changes

  • api.py error_check (now an instance method): on a 401 with a stored refresh token, force a silent refresh (ensure_valid_token(force=True)) and, on success, raise TokenRefreshed. A one-shot per-instance guard prevents any refresh/retry loop.
  • error_handling.api_error_handler (was a passthrough): catches TokenRefreshed, reloads the new token onto the instance, and retries the request once.
  • If the retry still 401s while a refresh token survives, it bails quietly (next visit / the proactive refresh recovers). The hard sign-in dialog is now reached only when no refresh token remains — a genuinely dead session.
  • Offline guard: while Kodi reports no internet (System.InternetState), ensure_valid_token skips the refresh instead of hanging ~15s on a dead connection; the stored token is kept and refreshed once connectivity returns. A forced post-401 recovery bypasses the guard.
  • New TokenRefreshed exception and kodi.connection_available() helper.

Backward compatibility

The private-credential 401 path is unchanged. No settings or stored-token format changes.
The only user-visible change is fewer needless re-login prompts. No new strings.

Testing

  • Expire/reject the access token mid-session → list reloads without a re-login prompt
  • With no refresh token stored → still prompts sign-in (dead session)
  • Offline → no hang; recovers on reconnect
  • Normal browsing/playback unaffected

…ogin

Previously a 401 from the Helix API showed a hard "OAuth token is required"
dialog and exited, even when a valid refresh token was still stored -- which
happens routinely when the short-lived access token lapses (Kodi or the
network only just came up after a reboot or an overnight gap). The proactive
refresh in Twitch.__init__ doesn't cover a token that expires or is rejected
mid-session.

error_check now treats a 401 with a stored refresh token as recoverable:
it forces a silent refresh (ensure_valid_token(force=True)) and, on success,
raises TokenRefreshed so api_error_handler reloads the new token onto the
instance and retries the request once -- no toast, no re-login. A one-shot
guard prevents any refresh/retry loop; if the retry still 401s while a
refresh token survives, it bails quietly (the next visit or the proactive
service refresh recovers). The hard sign-in dialog is now reached only when
no refresh token remains -- a genuinely dead session. The private-credential
401 path is unchanged.

Also add an offline guard: while Kodi reports no internet
(System.InternetState), ensure_valid_token skips the doomed refresh instead
of hanging ~15s on a dead connection; the stored token is kept and refreshed
once connectivity returns. A forced post-401 recovery bypasses the guard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant