Skip to content

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 toast

Generation 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

  1. Frontend sends cancelLogin IPC call
  2. Rust sends SIGKILL to the child aws sso login process
  3. The child process exits
  4. Generation counter prevents stale state from taking effect

Polling

useAuthPoller runs every 60 seconds:

  1. For each profile, compare current auth state against previous state
  2. If state transitions to "expired" and silent refresh fails → show notification
  3. If auto-relogin is enabled → call loginProfile automatically
  4. 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.