Important Notice: We do not sell any products. This website provides free online tools only.
How to Fix Too Many Redirects after Cloudflare Zero Trust Login
Tailgo ·
Set Session Cookie to SameSite=Lax
Too Many Redirects after Cloudflare Zero Trust Login, if your app gets stuck in an endless loop right after a successful Cloudflare Zero Trust (Access) login—especially when the URL includes a query string—there’s a good chance your own application’s session cookie is set to
SameSite=Strict. That setting blocks the cookie on the cross-site redirect back from your team domain (e.g., tailgo.cloudflareaccess.com) to your app (e.g., term.stack.my.id), so the app thinks you’re not logged in yet and bounces you back to Access. Rinse, repeat, boom: ERR_TOO_MANY_REDIRECTS.
Change your application’s session cookie to SameSite=Lax (and keep Secure on HTTPS). Lax allows cookies on top-level cross-site navigations (like the redirect from Zero Trust) while still protecting against most CSRF. If your app needs cookies inside iframes across domains, use SameSite=None; Secure instead.
Why this happens
The Zero Trust flow goes like this: user authenticates at your team domain → Access redirects back to your app → your app needs its own session cookie to recognize the user. WithSameSite=Strict, that cookie is not sent on the cross-site redirect, so your app doesn’t see a session and kicks the user back to sign-in, causing the loop.
The Fix (change your session cookie policy)
Below are concrete snippets for common stacks. The goal is the same everywhere:- Use
SameSite=Laxfor your app’s session cookie. - Ensure
Secureis enabled (you’re on HTTPS behind Cloudflare anyway). - Keep
HttpOnlyif you already use it (recommended).
Laravel / PHP
// config/session.php 'secure' => true, 'same_site' => 'lax', // was 'strict'
Native PHP (manual cookie)
setcookie('sid', $value, [ 'path' => '/', 'secure' => true, 'httponly' => true, 'samesite' => 'Lax', // was 'Strict' ]);
Express (Node.js)
app.use(session({ secret: 'super-secret', cookie: { secure: true, // behind HTTPS httpOnly: true, sameSite: 'lax' // was 'strict' } }));
Next.js (API Route / Middleware setting cookie)
res.setHeader('Set-Cookie', `sid=${val}; Path=/; HttpOnly; Secure; SameSite=Lax` );
Django
# settings.py SESSION_COOKIE_SECURE = True SESSION_COOKIE_SAMESITE = 'Lax' # was 'Strict' CSRF_COOKIE_SECURE = True CSRF_COOKIE_SAMESITE = 'Lax'
Nginx (as a last-resort sanitizer)
Ideally, set cookies in the app. If you can’t, modern Nginx can flag cookies:# In a server/location that proxies to your app: proxy_cookie_flags ~ secure samesite=lax;
Note: This requires a recent Nginx with proxy_cookie_flags support; otherwise use app-level config.
How to verify the fix
1) Browser DevTools
Open your app → DevTools → Application → Cookies. After logging in via Zero Trust, your app’s session cookie should show:Secure: trueSameSite: Lax
2) Curl redirect chain
curl -ILv "https://your.app.example/?probe=1" | sed -n 's/^< Location: /Location: /p'
You should see at most one hop from Access back to your app—no ping-pong between /cdn-cgi/access/login and your homepage.
When you might need SameSite=None
If your app truly needs cookies inside a cross-site iframe (or other embedded contexts), use:SameSite=None; Secure
Never use None without Secure. For plain top-level navigations (the normal Zero Trust redirect), Lax is typically perfect and more restrictive.
Quick checklist
- App session cookie: SameSite=Lax, Secure on.
- Try an incognito window after changing cookie policy.
- Still looping? Clear old cookies or hit:
https://your.app.example/cdn-cgi/access/logoutandhttps://<your-team>.cloudflareaccess.com/cdn-cgi/access/logout. - Optional: ensure your origin redirects preserve the query string:
return 301 https://$host$request_uri;
But I can log in successfully—why still looping?
You are authenticated at Access. The loop happens because your app’s session cookie didn’t ride along on the cross-site redirect (blocked bySameSite=Strict), so the app can’t tell you’re signed in yet.
Is Lax secure enough?
Yes for most web apps.Lax blocks third-party requests but allows top-level cross-site navigations—exactly what the Zero Trust callback is. Keep HttpOnly and Secure enabled.
Laravel
// config/session.php 'secure' => true, 'same_site' => 'lax';
Express
app.use(session({ secret: 'super-secret', resave: false, saveUninitialized: false, cookie: { secure: true, httpOnly: true, sameSite: 'lax' } }));
Django
SESSION_COOKIE_SECURE = True SESSION_COOKIE_SAMESITE = 'Lax'
Nginx
proxy_cookie_flags ~ secure samesite=lax;
That’s it. Switching your app’s session cookie from SameSite=Strict to Lax is the small tweak that stops the Zero Trust post-login redirect loop—without loosening security more than necessary.