api authentication ai_generated partial

google.auth.exceptions.RefreshError: ('invalid_grant: Token has been expired or revoked.',)

ID: api/google-oauth-refresh-token-revoked

Also available as: JSON · Markdown
70%Fix Rate
82%Confidence
3Evidence
2023-01-01First Seen

Version Compatibility

VersionStatusIntroducedDeprecatedNotes
any active

Root Cause

Google silently revokes refresh tokens after 6 months of inactivity, when user changes password, or when >50 tokens exist per client. The 50-token limit is barely documented.

generic

Workarounds

  1. 85% success Store refresh tokens per-user and reuse existing ones via prompt=none
    If user already has a refresh token in your DB, use it instead of initiating new OAuth flow
  2. 90% success Implement re-authentication flow that gracefully handles revocation
    try: creds.refresh(request) except RefreshError: redirect_to_oauth_consent()
  3. 88% success Use service accounts for server-to-server auth instead of user OAuth
    creds = service_account.Credentials.from_service_account_file('key.json', scopes=SCOPES)

Dead Ends

Common approaches that don't work:

  1. Store and reuse the refresh token indefinitely 88% fail

    Google has a hidden 50 refresh token limit per user per OAuth client. Token 51 silently invalidates token 1. Also, 6 months inactivity = revocation.

  2. Request a new refresh token on every auth flow 75% fail

    Each new token pushes out the oldest. If user has multiple devices, they kick each other out.