Skip to content

fix(auth): prevent re-triggering Google login after ESC cancellation - #2082

Closed
Red-Asuka wants to merge 1 commit into
google-gemini:mainfrom
Red-Asuka:main
Closed

fix(auth): prevent re-triggering Google login after ESC cancellation#2082
Red-Asuka wants to merge 1 commit into
google-gemini:mainfrom
Red-Asuka:main

Conversation

@Red-Asuka

@Red-Asuka Red-Asuka commented Jun 27, 2025

Copy link
Copy Markdown

TLDR

Fixed authentication dialog ESC key handling issues including Google login re-triggering and infinite retry loops. Implemented deferred auth settings persistence to preserve user configuration during cancellations, and enhanced error message handling to prevent ESC exit when errors are present.

Dive Deeper

Multiple ESC key handling issues were identified and resolved:

  1. Auth cancellation bug: When user cancels Google authentication with ESC, subsequent ESC presses would incorrectly re-trigger the auth flow instead of showing proper error message.

  2. Configuration corruption: The original approach of immediately saving selectedAuthType would break users' existing auth configurations in their settings.json when authentication fails or gets cancelled.

  3. Infinite retry loops: When authentication fails with errors (e.g., missing environment variables), pressing ESC would cause infinite loops between "Waiting for auth" and error dialog.

The solution implements a deferred authentication pattern with the following improvements:

  • Pending Auth Selection: Introduced pendingAuthSelection state to track auth choices without immediately persisting them to settings
  • Deferred Persistence: Auth settings are now only saved after successful authentication, preventing configuration corruption during failures/cancellations
  • Enhanced ESC Handling: ESC exit is blocked when error messages are present (|| errorMessage condition), requiring users to resolve issues before proceeding
  • Automatic Retry: Existing saved auth methods are automatically loaded as pending selections for seamless re-authentication

Reviewer Test Plan

Test Case 1: Auth Cancellation (Updated)

  1. Select "Login with Google" in the auth dialog
  2. Wait for "Waiting for auth..." message to appear
  3. Press ESC to cancel authentication
  4. Verify you return to the auth dialog with your original settings intact
  5. Press ESC again
  6. Verify it shows "You must select an auth method to proceed" error message instead of re-opening Google login

Test Case 2: Configuration Preservation (Enhanced)

  1. Ensure you have selectedAuthType configured in .gemini/settings.json
  2. Follow Test Case 1 steps but let authentication fail
  3. Verify your settings.json still contains the original selectedAuthType (not the failed attempt)
  4. Restart the application and verify auto-authentication still works with your saved settings

Test Case 3: Error Message Handling (Enhanced)

  1. Select "Login with Google" but ensure you have an account that will cause auth errors (e.g., missing GOOGLE_CLOUD_PROJECT)
  2. Complete authentication but let it fail with error message
  3. Press ESC in the auth dialog with error message displayed
  4. Verify it shows "You must select an auth method to proceed" instead of creating infinite retry loop
  5. Verify no invalid auth settings were saved to your configuration

Test Case 4: Deferred Persistence (New)

  1. Start with no saved auth configuration
  2. Select an auth method and intentionally cause authentication to fail
  3. Verify no auth settings were written to settings.json
  4. Select the same auth method and complete authentication successfully
  5. Verify auth settings are now properly saved to settings.json

Testing Matrix

🍏 🪟 🐧
npm run
npx
Docker
Podman - -
Seatbelt - -

Linked issues / bugs

#1735 (comment)

@umairidris

Copy link
Copy Markdown
Contributor

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

The pull request aims to fix a bug where cancelling Google authentication could lead to an infinite loop of auth prompts. The proposed change correctly clears the selected auth type from user settings. My review identifies a scenario where this fix is incomplete—if the auth type is set in workspace settings—and suggests a more robust state-based approach to fully resolve the issue.

Comment thread packages/cli/src/ui/hooks/useAuthCommand.ts Outdated
@scidomino

Copy link
Copy Markdown
Collaborator

I think there's probably a more elegant way to do this that doesn't involve introducing new state to pass between files. The whole problem stems from the fact that we are saving the auth method to the settings before we know that they work. We shouldn't do that. Instead of handleAuthSelect just saving changes to settings we should change it to be a useState that simply stores the user's selection. then have the Effect only save that selection to the settings if performAuthFlow succeeds.

You can make the changes or I can get to that later today.

@scidomino

Copy link
Copy Markdown
Collaborator

Actually. I realize I have a few bugs to fix in this area anyways. I'll take care of this today.

@Red-Asuka

Copy link
Copy Markdown
Author

@scidomino Thanks for the feedback! I've updated the PR to only save auth settings after successful authentication and removed the wasCancelled logic as suggested. Please take another look.

@scidomino

Copy link
Copy Markdown
Collaborator

This issue has been fixed in another PR so I will close this.

@scidomino scidomino closed this Jul 28, 2025
yeelam-gordon added a commit to yeelam-gordon/gemini-cli that referenced this pull request Apr 28, 2026
Two reliability follow-ups mirroring the kimi-cli PR google-gemini#2082 review:

- writeRuntimeStatus: switch the temp-file open from 'w' to 'wx' so the
  open succeeds only when the path does not already exist. The random
  UUID suffix already makes collision astronomically unlikely; the
  exclusive open (O_CREAT | O_EXCL) adds defense-in-depth against a
  pre-placed regular file or symlink at the temp path that 'w' would
  silently follow and overwrite.

- tests: add a regression test asserting that no .tmp.* file is left
  behind when the underlying rename raises. We force the failure by
  pre-placing a non-empty directory at the target path, which makes
  fs.renameSync fail on every supported platform and exercises the
  catch-block tmp cleanup path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
yeelam-gordon added a commit to yeelam-gordon/gemini-cli that referenced this pull request Apr 29, 2026
…witch

Mirrors kimi-cli PR google-gemini#2082 commit 0f79e348. When the same PID switches
to serving a different session id mid-flight, the previous session's
runtime.json must be dropped before the new session's record is written;
otherwise an external observer running a PID-liveness check would see
this PID mapped to BOTH sessions and treat both as live.

Gemini CLI has two such in-process session switches:

- '/clear' (clearCommand) -> resetNewSessionState(<freshUUID>)
- session-browser resume (useSessionBrowser) -> setSessionId(<resumedId>)

Both paths now:

1. Capture the OLD session dir before changing the session id.
2. Switch the session id (resetNewSessionState / setSessionId).
3. clearRuntimeStatus(oldSessionDir) to drop the stale claim.
4. writeRuntimeStatus(newSessionDir, ...) so the PID is observable
   under the new session id from this point on.

All four steps are best-effort; the runtime-status I/O is wrapped in
try/catch so a write failure on slow/network/read-only filesystems
never blocks the user-visible operation.

Adds clearRuntimeStatus() to the runtime-status module: synchronous,
swallows ENOENT/ENOTDIR (idempotent), all other I/O errors silenced.
Three new tests: removes existing file, idempotent on missing file,
no-op on missing dir.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
yeelam-gordon added a commit to yeelam-gordon/gemini-cli that referenced this pull request Apr 30, 2026
Two reliability follow-ups mirroring the kimi-cli PR google-gemini#2082 review:

- writeRuntimeStatus: switch the temp-file open from 'w' to 'wx' so the
  open succeeds only when the path does not already exist. The random
  UUID suffix already makes collision astronomically unlikely; the
  exclusive open (O_CREAT | O_EXCL) adds defense-in-depth against a
  pre-placed regular file or symlink at the temp path that 'w' would
  silently follow and overwrite.

- tests: add a regression test asserting that no .tmp.* file is left
  behind when the underlying rename raises. We force the failure by
  pre-placing a non-empty directory at the target path, which makes
  fs.renameSync fail on every supported platform and exercises the
  catch-block tmp cleanup path.
yeelam-gordon added a commit to yeelam-gordon/gemini-cli that referenced this pull request Apr 30, 2026
…witch

Mirrors kimi-cli PR google-gemini#2082 commit 0f79e348. When the same PID switches
to serving a different session id mid-flight, the previous session's
runtime.json must be dropped before the new session's record is written;
otherwise an external observer running a PID-liveness check would see
this PID mapped to BOTH sessions and treat both as live.

Gemini CLI has two such in-process session switches:

- '/clear' (clearCommand) -> resetNewSessionState(<freshUUID>)
- session-browser resume (useSessionBrowser) -> setSessionId(<resumedId>)

Both paths now:

1. Capture the OLD session dir before changing the session id.
2. Switch the session id (resetNewSessionState / setSessionId).
3. clearRuntimeStatus(oldSessionDir) to drop the stale claim.
4. writeRuntimeStatus(newSessionDir, ...) so the PID is observable
   under the new session id from this point on.

All four steps are best-effort; the runtime-status I/O is wrapped in
try/catch so a write failure on slow/network/read-only filesystems
never blocks the user-visible operation.

Adds clearRuntimeStatus() to the runtime-status module: synchronous,
swallows ENOENT/ENOTDIR (idempotent), all other I/O errors silenced.
Three new tests: removes existing file, idempotent on missing file,
no-op on missing dir.
@sripasg sripasg added the size/s A small PR label Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s A small PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants