google-gemini / google-gemini/gemini-cli

OAuth refresh token lost during token refresh, causing 'No refresh token is set' after ~1 hour

Open
#21,691 9 comments 0 reactions 1 assignee Claimed by @ProthamD View on GitHub
area/core effort/small help wanted kind/bug priority/p1 status/bot-triaged
Dominant language
TypeScript
Stars
107k
Forks
14.6k
Avg merge
2d 3h
Merged PRs (30d)
45

Description

## Problem

When Google OAuth refreshes an access token, the `tokens` event payload only contains the new `access_token` — it does **not** resend the `refresh_token`. However, both `OAuthCredentialStorage.saveCredentials()` and the file-based `cacheCredentials()` overwrite the stored credentials entirely, wiping out the existing refresh token.

This causes sessions to fail with `API Error: No refresh token is set` after the first access token expiry (~1 hour).

### Additionally

`deleteCredentials()` in both `FileTokenStorage` and `KeychainTokenStorage` throws an error when the credential doesn't exist (e.g., was already deleted). This causes a cascading "Failed to clear OAuth credentials" error loop when re-auth tries to clear credentials that are already gone, preventing users from re-authenticating.

## Steps to reproduce

1. Authenticate with Google OAuth
2. Use the CLI for >1 hour (until access token expires)
3. Send another message → `No refresh token is set`
4. CLI attempts to clear credentials and re-auth → repeated "Failed to clear OAuth credentials" errors

## Expected behavior

- Refresh tokens should be preserved when saving a token refresh (merge with existing rather than overwrite)
- Deleting non-existent credentials should be a no-op

## Environment

- macOS, using `GEMINI_FORCE_ENCRYPTED_FILE_STORAGE=true`
- Affects both encrypted (`OAuthCredentialStorage`) and file-based (`cacheCredentials`) storage paths

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.