Clerk: redirect loop after authentication [2026 fix]

Redirect loop after Clerk auth caused by missing or misconfigured redirect URL in dashboard. Add exact callback URL to Allowed redirect URLs.

Clerk: Redirect Loop After Authentication - Emergency Fix

TL;DR

Cause: Your Clerk dashboard's "Allowed redirect URLs" doesn't match your app's actual callback route. Fix: Add http://localhost:3000/auth/callback (or your production URL) to Clerk dashboard → Application → Allowed redirect URLs, then restart your dev server.

---

Exact Error Messages

You'll see one or more of these in your browser console or server logs:

``` [Clerk] Redirect URI mismatch: 'http://localhost:3000/auth/callback' not in allowed list ```

``` Error: Invalid redirect_uri. The provided redirect_uri is not in the list of allowed URIs ```

``` Infinite redirect loop detected. User authenticated but cannot return to application. ```

``` [ClerkProvider] User session exists but redirect back to app fails - possible CORS or redirect configuration issue ```

``` window.location.href loop: /sign-in → /auth/callback → /sign-in → /auth/callback... ```

---

Broken Code vs. Fixed Code

❌ BROKEN: Incomplete Clerk Configuration

```javascript // pages/auth/callback.js or app/auth/callback/route.js import { handleRedirectCallback } from '@clerk/nextjs';

export default function AuthCallback() { // Missing proper error handling + redirect URL not in dashboard return handleRedirectCallback(); } ```

Problem: Your callback route exists, but Clerk dashboard doesn't know about it.

✅ FIXED: Complete Configuration

Step 1: Update callback route

```javascript // pages/auth/callback.js (Next.js Pages Router) import { handleRedirectCallback } from '@clerk/nextjs'; import { useEffect } from 'react'; import { useRouter } from 'next/router';

export default function AuthCallback() { const router = useRouter();

useEffect(() => { handleRedirectCallback(); }, []);

return <div>Completing sign in...</div>; } ```

OR for App Router:

```typescript // app/auth/callback/route.ts import { handleRedirectCallback } from '@clerk/nextjs/server'; import { NextRequest, NextResponse } from 'next/server';

export async function GET(req: NextRequest) { const response = await handleRedirectCallback(); return response || NextResponse.redirect(new URL('/dashboard', req.url)); } ```

Step 2: Add to Clerk Dashboard

1. Go to [Clerk Dashboard](https://dashboard.clerk.com) 2. Select your application 3. Navigate to SettingsURLs 4. In Allowed redirect URLs, add: - Development: http://localhost:3000/auth/callback - Production: https://yourdomain.com/auth/callback 5. Click Save 6. Restart your dev server

Step 3: Verify ClerkProvider wrapper (if using React)

```javascript // _app.js or app/layout.js import { ClerkProvider } from '@clerk/nextjs';

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

---

Still Broken? Check These Too

1. Multiple conflicting redirect URLs

If you have both http://localhost:3000/auth/callback AND http://127.0.0.1:3000/auth/callback in your allowed list, Clerk may reject one. Use consistent localhost naming or remove duplicates.

2. Environment variable mismatch

Your NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY or CLERK_SECRET_KEY might point to a different Clerk application than where you added the redirect URL. Verify they match the dashboard application you're configuring.

3. Middleware intercepts callback route

If using Clerk's built-in middleware, it might redirect before your callback handler runs. Check [related: Clerk middleware configuration](/?guide=clerk-middleware) and ensure your callback route is not protected:

```javascript // middleware.ts export const config = { matcher: [ '/((?!auth/callback|_next/static|_next/image|favicon.ico).*)', ], }; ```

---

Quick Checklist

  • [ ] Callback route exists and matches dashboard URL exactly
  • [ ] Restarted dev server after dashboard changes (critical!)
  • [ ] Using correct NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY for this application
  • [ ] ClerkProvider wraps your entire app
  • [ ] No trailing slashes mismatch (/callback vs /callback/)
  • [ ] HTTPS in production, HTTP in localhost
  • [ ] Cleared browser cache and cookies
  • ---

    Related Issues

  • [Clerk authentication not persisting across pages](/?guide=clerk-session-persistence) — Session exists but gets cleared on redirect
  • [CORS errors with Clerk](/?guide=clerk-cors-fix) — When you see Access-Control-Allow-Origin blocks
  • ---

    Official Documentation

    📖 [Clerk Authentication Flow - Official Docs](https://clerk.com/docs/references/nextjs/clerk-provider) 📖 [Redirect URIs Configuration](https://clerk.com/docs/deployments/set-up-your-application#configuring-your-application-urls)

    ---

    Found a different variation? Drop it in the comments

    This guide covers Next.js + Clerk v4+. If you hit this with a different stack (SvelteKit, Remix, Astro) or older Clerk versions, please comment the exact error and setup below—we'll add your solution to this guide.

    🔥 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