Handle failed logins gracefully without automatic retries - #84
Merged
Merged
Conversation
popen2
force-pushed
the
claude/issue-83-jk36qb
branch
3 times, most recently
from
August 21, 2026 08:14
1d05a6d to
dd75d17
Compare
Follow-up to #82, which fixed the 500ms retry loop behind #83. Three things that fix leaves open, plus the parts of the login path around it. The one that matters: retryDelayMsAfterError() was applied to every non-abort failure, including one that happens *after* the token was renewed. Those retries re-enter getNewToken(), so a failing profiles or EKS step opened a login page every 60 seconds while the token it already held was valid for another eight hours — in default-browser mode, a tab a minute. scheduleAfterFailure() now checks for a valid token first and keeps the ordinary expiry schedule there. - Frost stopping after an abandoned login was invisible: the tray read `expiresAt`, so it announced "Next refresh 8 hours ago" with nothing scheduled. It now reads the scheduled time (getNextRefreshAt()) and says "Sign-in needed", and a single notification says so too — not when the user closed the window or refused the sign-in themselves, which LoginAbortedError now carries as `cancelledByUser`. - Repeated failures back off 1m→30m instead of asking AWS the same question every minute forever; the streak resets on a clean run. - AccessDeniedException ends the run like ExpiredTokenException already does, and SlowDownException widens the poll interval (RFC 8628 §3.5) instead of being logged and ignored. - Default `expiresIn`/`interval` when AWS omits them: the first made the poll loop exit before it ran, the second made the sleep NaN and the loop hot. - Describe the openExternal failure with describeError(), per AGENTS.md. - docs/docs/{credential-refresh,login,troubleshooting}.html describe the new behaviour, and AGENTS.md gains schedule.ts with the two rules that keep #83 fixed. Also removes the assert-based self-check block from schedule.ts. Verified with `npm run build`, `npm run lint`, and a headless harness that loads dist/aws-sso.js against stubbed electron and a faked SSO OIDC client (15 checks). The post-login-failure case is the one that changed against main: token valid for an hour with every later step failing opens 2 login pages in 70s on main, 1 here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MgEBPwgAkov8Q1nFyJ78mt
popen2
force-pushed
the
claude/issue-83-jk36qb
branch
from
August 21, 2026 08:25
dd75d17 to
e414ab8
Compare
popen2
enabled auto-merge
August 21, 2026 08:27
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.
Summary
This PR fixes issue #83 where failed login attempts were retried automatically every 500ms, causing multiple login tabs/windows to accumulate when a machine was left unattended. The fix distinguishes between different failure modes and applies appropriate retry strategies: logins that nobody completed are no longer retried automatically, while other transient failures back off exponentially.
Key Changes
Login abort handling: Added
cancelledByUserflag toLoginAbortedErrorto distinguish user-initiated cancellations (window closed, sign-in denied) from other failures. Abandoned logins are no longer retried on a timer.Exponential backoff for transient failures: Implemented exponential backoff for non-login failures (network issues, AWS errors) that double the retry delay with each consecutive failure, capped at 30 minutes. This prevents hammering AWS with repeated requests for permanent configuration issues.
Token validity checking: Added
hasValidToken()to detect when the token refresh succeeded but a downstream step (profile refresh, EKS scan) failed. These failures now keep the ordinary token expiry schedule instead of triggering error retries.Scheduled refresh tracking: Added
getNextRefreshAt()andcancelTokenRefresh()functions to expose the scheduled refresh time to the UI, allowing the tray to show "Sign-in needed" instead of claiming a refresh is due when one has been deliberately cancelled.Improved error handling in token polling:
SlowDownExceptionwith dynamic interval adjustment per RFC 8628AccessDeniedExceptionto detect user denial at identity providerdescribeError()wrapperErrorOptionswithcausefield to error constructorsNotification on abandoned login: Added
notifyLoginNeeded()to notify the user once when a login is abandoned (unless they closed the window themselves), keeping the browser clean while making the situation visible.Documentation updates: Updated troubleshooting and login documentation to explain the new behavior and fix for the tab accumulation issue.
Implementation Details
scheduleAfterFailure()function centralizes retry logic with three distinct paths: valid token (use expiry schedule), abandoned login (cancel refresh), or transient failure (exponential backoff).getNextRefreshAt()instead ofexpiresAtto accurately reflect whether Frost is actively waiting for a refresh or waiting for user action.schedule.tsto verify backoff behavior and edge cases.https://claude.ai/code/session_01MgEBPwgAkov8Q1nFyJ78mt