1 Commits

Author SHA1 Message Date
kone 0984773711 fix(gemini): skip token cache when expires_at is within refresh window
When a Gemini OAuth account receives a 401, ratelimit_service sets
expires_at=now() to force a refresh. Previously GetAccessToken would
return the stale cached token before checking expires_at, causing
repeated 401s until the cache TTL expired.

Fix: check needsRefresh before attempting cache lookup.
2026-06-09 01:00:11 +08:00
@@ -62,16 +62,16 @@ func (p *GeminiTokenProvider) GetAccessToken(ctx context.Context, account *Accou
cacheKey := GeminiTokenCacheKey(account) cacheKey := GeminiTokenCacheKey(account)
// 1) Try cache first. // 1) Try cache first — skip if token is already expired or within refresh skew.
if p.tokenCache != nil { expiresAt := account.GetCredentialAsTime("expires_at")
needsRefresh := expiresAt == nil || time.Until(*expiresAt) <= geminiTokenRefreshSkew
if !needsRefresh && p.tokenCache != nil {
if token, err := p.tokenCache.GetAccessToken(ctx, cacheKey); err == nil && strings.TrimSpace(token) != "" { if token, err := p.tokenCache.GetAccessToken(ctx, cacheKey); err == nil && strings.TrimSpace(token) != "" {
return token, nil return token, nil
} }
} }
// 2) Refresh if needed (pre-expiry skew). // 2) Refresh if needed (pre-expiry skew).
expiresAt := account.GetCredentialAsTime("expires_at")
needsRefresh := expiresAt == nil || time.Until(*expiresAt) <= geminiTokenRefreshSkew
if needsRefresh && p.refreshAPI != nil && p.executor != nil { if needsRefresh && p.refreshAPI != nil && p.executor != nil {
result, err := p.refreshAPI.RefreshIfNeeded(ctx, account, p.executor, geminiTokenRefreshSkew) result, err := p.refreshAPI.RefreshIfNeeded(ctx, account, p.executor, geminiTokenRefreshSkew)