From 098477371117513e508527558caf48f8dcd44280 Mon Sep 17 00:00:00 2001 From: kone Date: Tue, 9 Jun 2026 01:00:11 +0800 Subject: [PATCH] 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. --- backend/internal/service/gemini_token_provider.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/internal/service/gemini_token_provider.go b/backend/internal/service/gemini_token_provider.go index 172b9411..9eef46b0 100644 --- a/backend/internal/service/gemini_token_provider.go +++ b/backend/internal/service/gemini_token_provider.go @@ -62,16 +62,16 @@ func (p *GeminiTokenProvider) GetAccessToken(ctx context.Context, account *Accou cacheKey := GeminiTokenCacheKey(account) - // 1) Try cache first. - if p.tokenCache != nil { + // 1) Try cache first — skip if token is already expired or within refresh skew. + 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) != "" { return token, nil } } // 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 { result, err := p.refreshAPI.RefreshIfNeeded(ctx, account, p.executor, geminiTokenRefreshSkew)