Clerk: redirect loop after authentication [2026 fix]

Redirect URI mismatch or missing publishable key causes infinite loop. Fix: verify NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY and allowed redirect URLs in dashboard.

Clerk: Redirect Loop After Authentication [2026 Fix]

TL;DR

Cause: Your redirect URI in Clerk dashboard doesn't match your app's actual domain, or NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY is missing/invalid. Fix: Update Clerk dashboard redirect URLs to match your deployment domain AND verify your publishable key is set correctly in environment variables.

---

Exact Console Error Messages

Watch for these in your browser console or server logs:

``` 1. "Clerk: Unable to complete sign in. Redirect URI mismatch."

2. "Error: NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY is not set or invalid"

3. "TypeError: Cannot read property 'redirectUrl' of undefined at AuthenticatedRoute"

4. "POST https://[your-clerk-domain].clerk.accounts.com/v1/verify failed - Invalid redirect_uri"

5. "Warning: useAuth() called outside of <ClerkProvider>. Make sure your app root wraps all routes." ```

---

Broken Code vs. Exact Fix

Problem 1: Missing or Incorrect Environment Variable

BROKEN: ```javascript // .env.local (missing or wrong value) CLERK_SECRET_KEY=sk_test_xxx // Missing NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY entirely

// app.tsx import { ClerkProvider } from '@clerk/nextjs';

export default function App() { return ( <ClerkProvider> <YourApp /> </ClerkProvider> ); } ```

FIXED: ```javascript // .env.local (verified and complete) NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_abc123xyz... CLERK_SECRET_KEY=sk_live_abc123xyz...

// app.tsx (same structure works now because env is correct) import { ClerkProvider } from '@clerk/nextjs';

export default function App() { return ( <ClerkProvider publishableKey={process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY} > <YourApp /> </ClerkProvider> ); } ```

Problem 2: Redirect URL Mismatch in Dashboard

BROKEN: ```javascript // Your app deployed to: https://myapp.vercel.app // But Clerk dashboard configured with: http://localhost:3000 // Result: After sign-in, user sent to localhost (not your deployed domain) // Browser can't reach it → app refreshes → repeats auth → infinite loop ```

FIXED: ```javascript // Clerk Dashboard → Applications → [Your App] → Allowed redirect URLs // Add EXACTLY these (no trailing slashes): // Development: http://localhost:3000 // Production: https://myapp.vercel.app // Staging: https://staging-myapp.vercel.app

// Your code doesn't change, but the redirect now succeeds: import { useRouter } from 'next/navigation'; import { useAuth } from '@clerk/nextjs';

export default function Dashboard() { const router = useRouter(); const { isSignedIn } = useAuth();

if (isSignedIn) { // This will now redirect to correct domain router.push('/dashboard'); } return <div>Loading...</div>; } ```

Problem 3: ClerkProvider Wrapping Issue

BROKEN: ```javascript // pages/index.tsx (app router) import { useAuth } from '@clerk/nextjs';

export default function Home() { const { isSignedIn } = useAuth(); // ERROR: Called outside provider return isSignedIn ? <Dashboard /> : <SignIn />; }

// Missing provider wrapper at root level ```

FIXED: ```javascript // app/layout.tsx (app router) import { ClerkProvider } from '@clerk/nextjs';

export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <ClerkProvider> <html> <body>{children}</body> </html> </ClerkProvider> ); }

// app/page.tsx (now safe to use useAuth) import { useAuth } from '@clerk/nextjs';

export default function Home() { const { isSignedIn } = useAuth(); return isSignedIn ? <Dashboard /> : <SignIn />; } ```

---

Version-Specific Behavior

⚠️ EXPLICIT UNCERTAINTY: Clerk's redirect behavior changed between v4 and v5. If you're on v4 and upgraded without checking migration docs, redirect URL handling differs. Run npm list @clerk/nextjs to verify your version. This guide assumes v5 (current as of 2026).

---

Still Broken? Check These Too

1. CORS/Mixed Content: If development is http://localhost:3000 but you're testing production https://myapp.com, browser blocks it. Always use matching protocols (both http OR both https).

2. Vercel Environment Variables Not Synced: You updated .env.local but deployed without redeploying. Solution: redeploy your app after updating env vars, or manually set them in Vercel dashboard → Settings → Environment Variables.

3. Incorrect Clerk Instance: You have multiple Clerk projects (dev, staging, prod). Your code uses publishable key from wrong project. Check dashboard URL matches your app's intended environment.

---

Quick Debug Checklist

  • [ ] echo $NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY returns a value (starts with pk_)
  • [ ] Clerk dashboard Redirect URLs exactly match your deployed domain (copy-paste from deployment URL)
  • [ ] ClerkProvider wraps your entire app in layout.tsx or _app.tsx
  • [ ] No typos in env variable names
  • [ ] Redeployed after changing env vars
  • ---

    Related Guides

    [Clerk setup for Next.js 15](/?guide=clerk-nextjs-setup) | [Authentication redirect patterns](/?guide=auth-redirects)

    ---

    Official Documentation

    [Clerk Redirect URLs Configuration](https://clerk.com/docs/deployments/overview) [Clerk Environment Variables](https://clerk.com/docs/deployments/clerk-environment-variables)

    ---

    Found a different variation? Drop it in the comments.

    🔥 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