Clerk: redirect loop after authentication [2026 fix]

Redirect loop after Clerk auth caused by misconfigured callback URL or stale session state. Fix: Verify CLERK_REDIRECT_URL matches your domain and clear browser storage.

Clerk: Redirect Loop After Authentication [2am Emergency Fix]

TL;DR

Cause: Your Clerk redirect URL doesn't match your actual domain, or the session state is corrupted in browser storage. Fix: Set CLERK_REDIRECT_URL=https://yourdomain.com in .env.local and clear localStorage/sessionStorage in DevTools.

---

Real Console Error Messages

You'll see one or more of these exact errors:

``` Error: Redirect loop detected. Ensure CLERK_REDIRECT_URL is correctly configured. ```

``` undefined (reading 'redirectUrl') at AuthenticatedRoute.tsx:45 ```

``` warning: getAuth() returned null after redirect. Session may not be initialized. ```

``` [Clerk] Invalid redirect URI. Expected https://yourdomain.com but got http://localhost:3000 ```

``` Cookies are blocked or third-party cookies disabled. Auth session cannot persist. ```

---

Broken Code vs. Fixed Code

Problem 1: Missing or Mismatched Redirect URL

BROKEN: ```javascript // .env.local (WRONG - localhost only) CLERK_PUBLISHABLE_KEY=pk_test_... CLERK_SECRET_KEY=sk_test_... // CLERK_REDIRECT_URL is not set!

// pages/auth.tsx import { useAuth } from '@clerk/nextjs';

export default function AuthPage() { const { isSignedIn } = useAuth(); if (!isSignedIn) { return <SignInButton />; } return <Dashboard />; // Loops infinitely } ```

FIXED: ```javascript // .env.local (CORRECT - matches your actual domain) CLERK_PUBLISHABLE_KEY=pk_test_... CLERK_SECRET_KEY=sk_test_... CLERK_REDIRECT_URL=https://yourdomain.com NEXT_PUBLIC_CLERK_REDIRECT_URL=https://yourdomain.com

// pages/auth.tsx (with redirect guard) import { useAuth } from '@clerk/nextjs'; import { useRouter } from 'next/router'; import { useEffect } from 'react';

export default function AuthPage() { const { isSignedIn, isLoaded } = useAuth(); const router = useRouter(); useEffect(() => { if (isLoaded && isSignedIn) { router.push('/dashboard'); // Explicit redirect, not component return } }, [isLoaded, isSignedIn, router]); if (!isLoaded) return <div>Loading...</div>; if (isSignedIn) return null; // Return nothing while redirecting return <SignInButton />; } ```

Problem 2: Stale Session State in Browser

BROKEN: ```javascript // Middleware caches old session before env var was updated // middleware.ts import { authMiddleware } from '@clerk/nextjs';

export const config = { matcher: ['/((?!.+\\.[\\w]+$|_next).*)', '/'], };

export default authMiddleware(); // This uses cached redirectUrl from old environment ```

FIXED: ```javascript // middleware.ts - with explicit redirect handling import { authMiddleware, redirectToSignIn } from '@clerk/nextjs';

export const config = { matcher: ['/((?!.+\\.[\\w]+$|_next).*)', '/'], };

export default authMiddleware({ publicRoutes: ['/'], afterAuth(auth, req) { // If not authenticated and trying to access protected route if (!auth.userId && !auth.isPublicRoute) { return redirectToSignIn({ returnBackUrl: req.url }); } }, }); ```

THEN: In your browser DevTools (F12 → Application tab): ```javascript // Clear all Clerk-related storage Object.keys(localStorage).forEach(key => { if (key.includes('clerk') || key.includes('__clerk')) { localStorage.removeItem(key); } }); Object.keys(sessionStorage).forEach(key => { if (key.includes('clerk')) { sessionStorage.removeItem(key); } }); // Then reload page location.reload(); ```

---

Still Broken? Check These Too

1. Third-party cookies blocked in browser – Clerk requires cookies. Check DevTools → Settings → Cookies and disable "Block third-party cookies" for testing. For production, add your domain to allow list. See [related cookie debugging guide](/?guide=cookies).

2. Development vs. production mismatch – If CLERK_REDIRECT_URL=https://yourdomain.com but your app is on subdomain.yourdomain.com, Clerk rejects it as invalid. Update env var to match exactly, including subdomain. I'm uncertain if Clerk v0.19+ allows wildcard subdomains; check official docs.

3. SignInButton/SignUpButton missing callback prop – Some versions require explicit redirectUrl prop. Test with: <SignInButton redirectUrl="/dashboard" />. This behavior may vary between versions. See [authentication flow debugging](/?guide=auth-flow).

---

Found a Different Variation?

Drop it in the comments below! We update this guide based on real 2am incidents. Please include: (1) your Clerk SDK version, (2) exact error message, (3) your framework/version.

---

Official Resources

  • [Clerk Redirect URL Configuration](https://clerk.com/docs/deployments/configure-sign-in-redirect)
  • [Clerk NextJS Integration Guide](https://clerk.com/docs/quickstarts/nextjs)
  • [Session & Auth Middleware Docs](https://clerk.com/docs/references/nextjs/auth-middleware)
  • 🔥 0d
    LIVE
    ↓ PlanetScale rage spiking •⚠ Vercel pricing complaints •↑ Railway gaining fast •↑ Supabase happiness rising •↑ Resend loved by devs •↓ PlanetScale rage spiking •⚠ Vercel pricing complaints •↑ Railway gaining fast •↑ Supabase happiness rising
    DEVELOPER PAIN RADAR // Loading...

    Developers complain.
    Opportunities appear.

    We track what developers are struggling with today — and what opportunities that creates.

    —
    guides today
    —
    avg happiness
    🔥 Pain
    📖 Guides
    🔭 Explore
    👤 Mine
    🔥 Pain Radar — rage scores today
    ↗ share
    💡 Opportunity Feed — pain = market gap
    📈 Tool Momentum
    all scores →
    📖 Latest Guide
    all guides →
    📖 All Guides
    📊 Tool Scores
    + Submit
    📰 Hacker News
    ➕ Submit a Tool
    ← back