Skip to content

Fix Gemini OAuth refresh when CLI oauth2.js is missing#1984

Merged
steipete merged 8 commits into
steipete:mainfrom
Yuxin-Qiao:fix/gemini-oauth-recovery
Jul 11, 2026
Merged

Fix Gemini OAuth refresh when CLI oauth2.js is missing#1984
steipete merged 8 commits into
steipete:mainfrom
Yuxin-Qiao:fix/gemini-oauth-recovery

Conversation

@Yuxin-Qiao

@Yuxin-Qiao Yuxin-Qiao commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #1978.

When Gemini access tokens expire, CodexBar must read OAuth client credentials from the installed Gemini CLI. If oauth2.js cannot be found, refresh failed early with Could not find Gemini CLI OAuth configuration before Google could return the consumer-tier migration signals handled by #1931.

This adds broader OAuth client discovery and clearer recovery guidance.

Changes

  • Add GeminiOAuthConfig env helpers for GEMINI_OAUTH_CLIENT_ID, GEMINI_OAUTH_CLIENT_SECRET, and GEMINI_OAUTH2_JS_PATH
  • Resolve OAuth client credentials in order: env override → installed CLI → explicit oauth2.js path → known Homebrew/npm global install paths → Homebrew Cellar/opt libexec package roots
  • Isolate OAuth env overrides via @TaskLocal so parallel Gemini suites cannot pick leaked process-wide credentials
  • Replace the opaque missing-config error with combined Gemini CLI repair + Antigravity migration guidance for consumer accounts, while noting Workspace/education accounts should keep using Gemini
  • Add fixture-backed API/config tests (including no-binary Homebrew Cellar discovery) and update docs/gemini.md

Testing

  • swift test --filter 'GeminiOAuthConfigTests|GeminiOAuthRecoveryAPITests' (5/5 passed)
  • swiftformat + swiftlint --strict on changed files

Live proof (redacted)

Verified on 2026-07-08 against PR head 20e709312 with a real ~/.gemini/oauth_creds.json that still had a refresh token.

Setup shared by both runs

  • Forced access token to an expired marker and set expiry_date in the past
  • Pointed GEMINI_CLI_PATH at a fake gemini binary that has no oauth2.js / OAuth client constants
  • Used debug CLI: .build/debug/CodexBarCLI usage --provider gemini --format json --pretty --status
  • Secrets/emails redacted below; no client secret pasted

Proof 1 — GEMINI_OAUTH2_JS_PATH recovery

GEMINI_CLI_PATH=<fake-gemini-without-oauth>
GEMINI_OAUTH2_JS_PATH=/opt/homebrew/lib/node_modules/@google/gemini-cli/node_modules/@google/gemini-cli-core/dist/src/code_assist/oauth2.js
.build/debug/CodexBarCLI usage --provider gemini --format json --pretty --status
exit_code=0

Redacted stdout:

[
  {
    "provider" : "gemini",
    "source" : "oauth-api",
    "usage" : {
      "accountEmail" : "<redacted-email>",
      "identity" : {
        "accountEmail" : "<redacted-email>",
        "loginMethod" : "Paid",
        "providerID" : "gemini"
      },
      "loginMethod" : "Paid",
      "primary" : {
        "resetDescription" : "Resets in 23h 59m",
        "usedPercent" : 0,
        "windowMinutes" : 1440
      },
      "updatedAt" : "2026-07-08T14:11:08Z"
    }
  }
]

Post-run credential check: access token no longer the expired marker; expiry_date is in the future; refresh_succeeded=true.

Proof 2 — known install-path recovery (no oauth2 path / client env)

Same expired credential + fake CLI, with GEMINI_OAUTH2_JS_PATH / GEMINI_OAUTH_CLIENT_* unset so discovery must use known Homebrew/npm install paths:

GEMINI_CLI_PATH=<fake-gemini-without-oauth>
unset GEMINI_OAUTH2_JS_PATH GEMINI_OAUTH_CLIENT_ID GEMINI_OAUTH_CLIENT_SECRET
.build/debug/CodexBarCLI usage --provider gemini --format json --pretty --status
exit_code=0
provider=gemini source=oauth-api loginMethod=Paid usedPercent=0
refresh_succeeded=true

Both proofs show the new recovery path can refresh past a missing in-CLI oauth2.js layout without the old Could not find Gemini CLI OAuth configuration dead-end.

Related

Made with Cursor

@clawsweeper

clawsweeper Bot commented Jul 8, 2026

Copy link
Copy Markdown

Codex review: needs maintainer review before merge. Reviewed July 11, 2026, 7:19 AM ET / 11:19 UTC.

Summary
The PR adds explicit and installed-package Gemini OAuth client discovery so expired sessions can refresh when oauth2.js is absent, with recovery guidance, focused tests, and documentation.

Reproducibility: yes. Current-main source has a deterministic missing-client failure for expired tokens, and the PR body provides redacted live runs showing successful refresh through both new discovery paths.

Review metrics: 3 noteworthy metrics.

  • Changed surface: 9 files, +538/-72. The patch changes core OAuth refresh selection, recovery messaging, tests, documentation, and one release-note entry.
  • Focused recovery coverage: 5 tests added. The new tests cover configuration completeness and three distinct expired-token recovery paths.
  • Final-head refinements: 2 owner-authored commits. The repository owner directly adjusted credential precedence and parallel-test isolation after earlier review cycles.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #1978
Summary: This PR is the direct fix candidate for the open Gemini refresh blocker; nearby merged work addresses downstream migration and plan display.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦞 diamond lobster
Proof: 🦞 diamond lobster
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Risk before merge

  • [P1] The newly supported GEMINI_OAUTH_CLIENT_ID and GEMINI_OAUTH_CLIENT_SECRET values intentionally take precedence over installed CLI credentials, making this an upgrade-sensitive auth-source contract for launches that set those variables.
  • [P1] The live transcript was captured before the last two owner-authored commits, although those commits narrow precedence and isolate tests rather than changing the two demonstrated recovery outcomes.
  • [P1] Required Linux and macOS checks for the force-pushed exact head have not yet completed.

Maintainer options:

  1. Accept the owner-refined auth contract (recommended)
    Merge after required checks pass, preserving explicit configuration precedence and the bounded installed-package fallbacks as supported Gemini recovery behavior.
  2. Narrow explicit configuration support
    If environment-provided OAuth secrets should not be a supported interface, remove those knobs while retaining explicit-file and installed-package recovery.

Next step before merge

  • No automated repair is needed; required checks should gate normal maintainer merge of the exact head.

Security
Cleared: The patch introduces no new dependency, executable download, workflow permission, or network destination; OAuth secrets remain within the existing local refresh flow.

Review details

Best possible solution:

Land the owner-refined explicit-first resolver after exact-head checks pass, retaining the fixture coverage and documented recovery options for affected Workspace and education accounts.

Do we have a high-confidence way to reproduce the issue?

Yes. Current-main source has a deterministic missing-client failure for expired tokens, and the PR body provides redacted live runs showing successful refresh through both new discovery paths.

Is this the best way to solve the issue?

Yes. Explicit credentials first, installed CLI discovery next, and bounded known-path fallback directly repair the compatibility failure without adding automatic provider switching or a competing usage source.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 98de97833505.

Label changes

Label changes:

  • add rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • remove rating: 🐚 platinum hermit: Current PR rating is rating: 🦞 diamond lobster, so this older rating label is no longer current.

Label justifications:

  • P0: The linked report blocks affected users from obtaining Gemini usage and recovery otherwise requires terminal-level configuration or support.
  • merge-risk: 🚨 auth-provider: The PR changes which OAuth client credentials are selected and sent when refreshing existing Gemini sessions.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR provides redacted after-fix terminal output for explicit-file and known-install recovery, including successful exit and refreshed credential state.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR provides redacted after-fix terminal output for explicit-file and known-install recovery, including successful exit and refreshed credential state.
Evidence reviewed

What I checked:

Likely related people:

  • steipete: Authored the exact-head credential-precedence and binary-isolation refinements and has the strongest sampled history in the Gemini provider area. (role: repository owner and recent area contributor; confidence: high; commits: 6c7eb9f5f1b7, 87eaaab9a1bb; files: Sources/CodexBarCore/Providers/Gemini/GeminiStatusProbe.swift, Sources/CodexBarCore/PathEnvironment.swift)
  • Yuxin-Qiao: Authored the central recovery implementation and previously contributed the merged consumer-tier migration behavior that this refresh path complements. (role: Gemini recovery feature contributor; confidence: high; commits: 67604373bfea, 9491e3af0582, 63c69fdcc47f; files: Sources/CodexBarCore/Providers/Gemini/GeminiStatusProbe.swift, Tests/CodexBarTests/GeminiOAuthRecoveryAPITests.swift, docs/gemini.md)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (7 earlier review cycles)
  • reviewed 2026-07-08T03:53:34.897Z sha b64c37b :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-08T05:52:46.902Z sha 62115c1 :: needs real behavior proof before merge. :: [P2] Cover the Cellar Homebrew layout in fallback discovery | [P2] Isolate OAuth env overrides across Gemini tests
  • reviewed 2026-07-08T14:17:44.110Z sha 20e7093 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-08T14:24:14.357Z sha 20e7093 :: needs changes before merge. :: [P2] Avoid process-wide CLI overrides in tests
  • reviewed 2026-07-09T15:10:09.758Z sha 7c32bc4 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-09T15:39:41.025Z sha 21efe43 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-09T16:53:59.924Z sha 4f13206 :: needs maintainer review before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P0 Emergency: data loss, security bypass, crash loop, or unusable core runtime. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. labels Jul 8, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 62115c1624

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +119 to +120
setenv("GEMINI_OAUTH_CLIENT_ID", "env-client-id", 1)
setenv("GEMINI_OAUTH_CLIENT_SECRET", "env-client-secret", 1)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Isolate OAuth env overrides across suites

Because the resolver now checks GEMINI_OAUTH_CLIENT_ID/GEMINI_OAUTH_CLIENT_SECRET before the fake Gemini CLI, these process-wide overrides can bleed into other Gemini fetch tests while Swift Testing runs suites in parallel. @Suite(.serialized) only orders tests inside this suite, so a concurrent GeminiStatusProbeAPITests case that installs a fake CLI and expects test-client-id can intermittently send env-client-id instead; isolate the OAuth client via injection or serialize all suites that mutate these globals.

Useful? React with 👍 / 👎.

Comment on lines +1129 to +1132
"/opt/homebrew/lib/node_modules/@google/gemini-cli-core/\(oauthFile)",
"/opt/homebrew/lib/\(nestedOAuthFile)",
"/usr/local/lib/node_modules/@google/gemini-cli-core/\(oauthFile)",
"/usr/local/lib/\(nestedOAuthFile)",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Cover the real Homebrew formula layout

When Gemini is installed by Homebrew but the app cannot resolve /opt/homebrew/bin/gemini or /usr/local/bin/gemini from its captured PATH, this fallback still misses the credentials: the repo's Homebrew fixture models the package under Cellar/.../libexec/lib/node_modules/@google/gemini-cli/bundle, while these newly added probes only look under lib/node_modules. In that common Homebrew scenario the recovery path still falls through to the missing-config error, so add the Homebrew binary paths to discovery or probe the Cellar/libexec layout here.

Useful? React with 👍 / 👎.

@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

CI is fully green on 62115c16 (linux x64/arm64 + 4 macOS shards + lint-build-test). Previous review ended with Codex ETIMEDOUT infrastructure failure, not a code verdict.

@clawsweeper

clawsweeper Bot commented Jul 8, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Addressed the review rank-up items on 20e709312:

  1. Homebrew Cellar/libexec fallback — known-install discovery now walks Cellar/opt libexec package roots and has a fixture test that refreshes when the resolvable gemini binary has no OAuth config.
  2. Env isolationGEMINI_OAUTH_* overrides use @TaskLocal (GeminiOAuthConfig.$environmentOverride) instead of process-wide setenv, so parallel Gemini suites are not contaminated.
  3. Redacted live expired-token refresh proof — posted in the PR body (fake CLI without oauth2.js; recovery via GEMINI_OAUTH2_JS_PATH and via known install paths). Both runs exited 0 with source: oauth-api / Paid usage after refresh.

@clawsweeper

clawsweeper Bot commented Jul 8, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 8, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 20e709312b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


let binURL = try env.writeFakeGeminiCLI(includeOAuth: false)
let previousGeminiPath = ProcessInfo.processInfo.environment["GEMINI_CLI_PATH"]
setenv("GEMINI_CLI_PATH", binURL.path, 1)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid process-wide CLI path overrides in parallel tests

When Swift Testing runs this new serialized suite alongside other serialized Gemini suites, this process-wide GEMINI_CLI_PATH mutation can bleed into an in-flight GeminiStatusProbeAPITests or GeminiConsumerTierMigrationTests case that is resolving its own fake CLI. That can make refresh requests use the wrong fixture credentials or fail intermittently even though each suite is internally serialized; prefer injecting the CLI path/task-localizing it or serializing all suites that mutate this variable together.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. merge-risk: 🚨 automation 🚨 Merging this PR could break CI, automerge, proof capture, label sync, or automation. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jul 8, 2026
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. merge-risk: 🚨 automation 🚨 Merging this PR could break CI, automerge, proof capture, label sync, or automation. labels Jul 9, 2026
Yuxin-Qiao and others added 2 commits July 11, 2026 12:05
Add env overrides, GEMINI_OAUTH2_JS_PATH, and known global install-path
discovery so token refresh can proceed without a resolvable gemini binary
layout. Surface combined Gemini/Antigravity recovery guidance when OAuth
client discovery still fails.

Fixes steipete#1978

Co-authored-by: Cursor <cursoragent@cursor.com>
Move OAuth discovery helpers out of the main probe struct and split
recovery API tests into their own file to satisfy type_body_length.

Co-authored-by: Cursor <cursoragent@cursor.com>
Yuxin-Qiao and others added 6 commits July 11, 2026 12:05
Add Cellar/opt libexec fallback when the gemini binary cannot yield
credentials, inject OAuth env via TaskLocal so parallel Gemini suites
stay uncontaminated, and document the expanded discovery path.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@steipete steipete force-pushed the fix/gemini-oauth-recovery branch from 4f13206 to 87eaaab Compare July 11, 2026 11:15
@clawsweeper clawsweeper Bot added rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jul 11, 2026
@steipete steipete merged commit 820bfa1 into steipete:main Jul 11, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. P0 Emergency: data loss, security bypass, crash loop, or unusable core runtime. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gemini stat cannot display because of Gemini CLI error.

2 participants