Auth state machine
Login flow
User clicks "Login" on profile P
│
▼
resolveLoginTarget(P) ──► walks source_profile chain to find SSO root
│
▼
checkAuthStatus(root)
│
├── valid? ──► skip browser, mark P as active login
│
└── expired?
│
▼
loginProfile(root) ──► opens browser for SSO sign-in
│
▼
checkAuthStatus(root)
│
├── valid? ──► mark P as active login, optionally set default
│
└── invalid? ──► show warning toastGeneration counter
Each login() call increments a per-profile generation counter. The finally block only clears authing if the generation is still current. This prevents a stale finally (from a cancelled login that resolves after a new login starts) from hiding the loading state.
typescript
const gen = (loginGen.current[name] ?? 0) + 1;
loginGen.current[name] = gen;
// ... async login ...
finally {
if (loginGen.current[name] === gen) {
setAuthing(name, false);
}
}Cancel login
- Frontend sends
cancelLoginIPC call - Rust sends SIGKILL to the child
aws sso loginprocess - The child process exits
- Generation counter prevents stale state from taking effect
Polling
useAuthPoller runs every 60 seconds:
- For each profile, compare current auth state against previous state
- If state transitions to "expired" and silent refresh fails → show notification
- If auto-relogin is enabled → call
loginProfileautomatically - Every 5 minutes → silent re-scan of
~/.aws/config
Silent refresh detection
When a profile's auth state transitions from "expired" to "authenticated" between polls, Mimic detects that the AWS CLI silently refreshed the token (because the user ran an AWS CLI command). The timer updates to the new expiry.
Sync organization
synchronizeOrganization() also uses a generation counter (syncGeneration) for stale-state protection. The finally block only clears syncingSession if the generation hasn't been superseded.