login redirect loop between the app and the identity provider after enabling SSO
A step-by-step skill for fixing SSO login redirect loops between the app and the identity provider: session cookie attributes, callback URL matching, clock skew, and proxy scheme handling. Use when enabling SAML or OIDC produces an endless app to IdP to app bounce. Triggers: 'SSO redirect loop', 'login loop', 'SAML loop', 'OIDC redirect loop'. Not for: failed logins with an error page, IdP-side authentication failures, or logout loops.
login redirect loop between the app and the identity provider after enabling SSO
TL;DR
The app bounces you to the identity provider, the provider sends you back, the app doesn't recognize the session, repeat. Almost always the session cookie isn't surviving the round trip: wrong SameSite or Secure attributes, a callback URL mismatch, or the app and provider disagreeing on the session. Fix the cookie first.
login redirect loop between the app and the identity provider after enabling SSOUse this when
- Enabling SAML or OIDC produces an endless bounce between your app and the identity provider
- The loop starts immediately after SSO is turned on, with no error page
- The browser network log shows app to IdP to callback to app, repeating
- It works in one browser but loops in another
Not for this skill when
- Login fails with a visible error page (read the error instead)
- The identity provider itself rejects the credentials
- The loop happens at logout rather than login
Steps
- Watch one loop in the browser network panel with "preserve log" on. Note the exact sequence: app to IdP, IdP POST back to the callback, app redirecting to IdP again.
Expected: you see the callback request returning a redirect instead of establishing a session.
- Inspect the session cookie on the callback response. On HTTPS it must carry the Secure attribute, and SameSite must suit the flow (Lax usually works for top-level GET callbacks; None plus Secure for POST-back flows).
Expected: Set-Cookie present with the right attributes. If the cookie never appears, the app isn't persisting the session at all.
- Compare the callback URL registered at the IdP with the one the app sends, character for character: scheme, host, port, trailing slash.
Expected: exact match. An http vs https or trailing-slash difference makes the IdP mint tokens for a callback the app doesn't trust.
- Check clock skew between the app server and the IdP. SAML and OIDC both reject assertions outside a tight time window, which looks like a loop when the app retries:
date -uRun it on the app server and compare to a known-good clock. Expected: within a minute. If not, fix NTP.
- If the app sits behind a proxy, confirm it sees the original scheme (X-Forwarded-Proto) so it doesn't set cookies for http while serving https.
Expected: one clean login, session cookie present, no second trip to the IdP.
Variant: loop only in Safari or Firefox
Stricter cookie handling there; SameSite=None without Secure is rejected outright. Fix the attributes rather than blaming the browser.
Variant: loop after enabling force authentication at the IdP
The IdP never shows an existing session, so it always re-challenges. Relax the force-authn setting unless you truly need it on every login.
Variant: WordPress or Discourse SSO loops
Same cookie-first debugging, plugin settings second. Check the plugin's callback URL and cookie domain settings before anything else.
Why this happens
SSO is a two-hop dance that only works if the session established on the return hop sticks. Anything that drops the cookie, attribute mismatch, domain mismatch, the app clearing the session on the callback, restarts the dance from the top, and both sides happily loop forever.
Edge cases and pitfalls
- An ad blocker or privacy extension eating third-party cookies can cause loops no config change fixes; test in a clean profile.
- If the IdP session lifetime is shorter than the app's, users loop at re-auth; align the lifetimes.
- Log the SAML or OIDC error at the app before assuming it's the cookie; sometimes the IdP is rejecting the request and the app retries blindly.
- Sticky sessions matter: if the callback lands on a different app instance with in-memory sessions, the session is gone; use a shared session store.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_L4foQWgEDdpky2sUyRQdfg