Google OAuth Refresh Token Causes Infinite Redirect Loop After Logout and Re-Login in Django App

I'm implementing Google OAuth2 login in a Django-based application. The initial login works fine — I receive both an access token and a refresh token from Google. I only save the refresh token, since the access token expires in one hour and isn't usable beyond that.

After login, the user can use the app and perform all actions. Upon logout, I clear the session and remove stored credentials.

However, when the user tries to log in again, the app gets stuck in an infinite redirect loop — Google redirects back immediately to my app (since consent was already granted), and my app fails to authenticate the user because the refresh token exchange fails, so it starts the login process again. This cycle repeats endlessly.

Even though I save the refresh token from the first login and attempt to reuse it, this still doesn't fix the issue. I suspect the refresh token gets invalidated silently (possibly by re-login, password change, or Google's internal rotation policy).

Additionally, this breaks background scheduled tasks (like Gmail API-based scheduled emails), because they depend on the saved refresh token to generate access tokens — which fails if the token becomes invalid.

Authorization

authorization_url, state = flow.authorization_url(
    access_type='offline',
    include_granted_scopes='true'
    # Removed 'prompt=consent' to avoid unnecessary refresh token regeneration
)

Saving Credentials (On Successful Login):

credentials = flow.fetch_token(code=code)
request.session['credentials'] = credentials_to_dict(credentials)

Refreshing Token:

if credentials.expired and credentials.refresh_token:
    credentials.refresh(Request())

Logout:

def logout(request):
    django_logout(request)
    request.session.flush()

What I Need Help With:

  • Is there a reliable way to persist refresh tokens that won't cause this redirect loop after logout?
  • Is Google invalidating refresh tokens due to session policies, token reuse limits, or silent revocation?
  • How can I structure this OAuth flow so that scheduled jobs (like Gmail API calls) can continue working reliably after logout?

Environment:

  • Django 4.x
  • Python 3.10
  • google-auth, google-auth-oauthlib
  • Google OAuth Web Application

References Checked

  • Google OAuth Refresh Token Expiry
  • OAuth2 redirect loop after logout

Any insights, fixes, or suggestions are welcome. Thanks in advance!

Back to Top