Skip to content

OAuth login gets stuck in infinite redirect loop outside the iframe — callback doesn't clear stale session cookie #13634

Description

@lpuzzolokodear

Description

When the OAuth session cookie (set by the Starlette session middleware Gradio uses to store OAuth state/nonce/code_verifier during the login flow) becomes stale or invalid, the /login/callback handler does not clear it before redirecting back to retry. This causes an infinite redirect loop that persists even outside the iframe, which the existing mitigation in #8533 / PR #8951 does not cover.

PR #8951 detects "too many redirects" (MAX_REDIRECTS = 2) and, when exceeded, redirects the user to the non-iframe SPACE_HOST URL — under the assumption that the root cause is always third-party cookies being blocked inside the Spaces iframe. That escape hatch does nothing when the user is already on the direct, non-iframe *.hf.space URL: the loop just continues there with no further fallback, until the browser gives up with ERR_TOO_MANY_REDIRECTS.

Steps to reproduce

Hard to reproduce deterministically (it depends on the browser already holding a stale session cookie from a previous failed/interrupted OAuth attempt for that Space), but once a browser is in this state:

  1. Open a Gradio Space with hf_oauth: true directly at its https://<space>.hf.space/ URL (not embedded in the huggingface.co/spaces/... iframe).
  2. Click "Sign in with Hugging Face".
  3. Observe the request chain in DevTools → Network (with "Preserve log"):
    • GET /login/huggingface?_nb_redirects=N&_target_url=... (on the Space)
    • GET /oauth/authorize?... → 303 (on huggingface.co)
    • GET /login/callback?_target_url=... → 307 (on huggingface.co)
    • back to GET /login/huggingface?_nb_redirects=N+1&... (on the Space)
    • repeats indefinitely, _nb_redirects climbing each cycle, never resolving
  4. Eventually Chrome shows: "<space>.hf.space te redireccionó demasiadas veces. ERR_TOO_MANY_REDIRECTS"

Root cause (as far as I can tell without server-side access)

Checked in DevTools → Application → Cookies for the Space's own *.hf.space domain: a session cookie is present (separate from huggingface.co's own token/session cookies). This is the Starlette SessionMiddleware cookie Gradio's OAuth code uses to hold state across the redirect chain. Manually deleting only this one cookie for the Space's domain immediately fixes the login — no need to clear cookies for huggingface.co or anything else.

This strongly suggests the callback handler, on detecting invalid/mismatched OAuth state (or any failure during the authorize/callback round trip), redirects back to retry the flow without clearing/resetting the session cookie first — so every subsequent attempt fails identically against the same stale state, forever, until a human manually intervenes at the browser level.

Suggested fix

In the /login/callback handler (gradio/oauth.py), when OAuth state validation fails (or the token exchange otherwise fails) instead of only redirecting back to /login/huggingface with an incremented _nb_redirects, also clear/reset the session cookie (or at least the OAuth-related keys within it) so the next attempt starts from a clean state instead of repeating the same failure. The existing MAX_REDIRECTS/non-iframe-escape logic in PR #8951 could stay as a secondary safety net, but shouldn't be the only recovery path — it doesn't help when the loop is already happening outside the iframe.

Environment

  • Gradio SDK version: 6.3.0
  • Hosted on Hugging Face Spaces (ZeroGPU hardware)
  • hf_oauth: true, hf_oauth_scopes: [contribute-repos]
  • Reproduced in Chrome (stable), both inside the huggingface.co/spaces/... iframe and directly at the *.hf.space URL
    \n\n## Before / after Spaces\n\n- Before fix\n- After fixdraft PR #13641

Before / after Spaces

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions