Clerk: redirect loop after authentication [2026 fix]

Your redirect URI doesn't match Clerk's allowlist or middleware runs after auth—add exact URI match and reorder Next.js middleware.

Clerk: Redirect Loop After Authentication - 2am Emergency Fix

TL;DR

Cause: Your application's redirect URI doesn't match Clerk's configured allowlist, or your Next.js middleware authentication logic runs *after* the redirect attempt.

Fix: Add your exact callback URL to Clerk Dashboard → Advanced → Redirect URIs, and ensure clerkMiddleware() executes *before* any custom redirect logic.

---

Real Console Error Messages

Look for these exact errors in your browser console (F12 → Console tab):

``` 1. GET http://localhost:3000/auth/callback?code=abc123 302 Found Location: http://localhost:3000/auth/callback (redirect loop detected)

2. Error: Invalid redirect_uri. The URI "http://myapp.com/auth/callback" is not whitelisted in your Clerk application settings.

3. clerk.redirect() called with URI that failed allowlist validation

4. [Clerk] Unable to complete sign-in. Redirect URI mismatch: expected "https://yourdomain.com" but got "http://yourdomain.com"

5. Next.js middleware: rewrites redirected to /auth/callback infinitely because Clerk session not yet established ```

---

Broken Code vs. Exact Fix

Problem 1: Missing Redirect URI in Clerk Dashboard

❌ Broken (what happens) ```javascript // app/auth/callback/route.ts export async function GET(req: Request) { const { searchParams } = new URL(req.url); const code = searchParams.get('code'); // Clerk tries to redirect here, but this URI isn't allowlisted // Result: 302 → 302 → 302 (infinite loop) } ```

✅ Fixed 1. Go to [Clerk Dashboard](https://dashboard.clerk.com) 2. Select your application 3. Navigate to Settings → Advanced → Redirect URIs 4. Add exact URIs: - http://localhost:3000 (development) - https://yourdomain.com (production) - https://yourdomain.com/auth/callback (if using custom callback) 5. Save and wait 30 seconds for cache invalidation

Problem 2: Middleware Ordering (Next.js)

❌ Broken ```typescript // middleware.ts (WRONG ORDER) import { NextResponse } from 'next/server'; import { clerkMiddleware } from '@clerk/nextjs/server';

export default function middleware(request: Request) { // ❌ Custom logic runs FIRST, before Clerk validates session if (!request.nextUrl.pathname.startsWith('/api')) { // Clerk session doesn't exist yet—redirect triggers return NextResponse.redirect(new URL('/auth/signin', request.url)); } // ❌ Clerk runs AFTER redirect already happened return clerkMiddleware()(request); }

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

✅ Fixed ```typescript // middleware.ts (CORRECT ORDER) import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'; import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server';

const isProtectedRoute = createRouteMatcher(['/dashboard(.*)']);

export default clerkMiddleware((auth, request) => { // ✅ Clerk middleware wraps everything // ✅ Session is NOW validated before your logic runs const { userId } = auth(); // Now safe to check authentication if (isProtectedRoute(request) && !userId) { return NextResponse.redirect( new URL('/sign-in?redirect_url=' + request.nextUrl.pathname, request.url) ); } });

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

Problem 3: Protocol Mismatch (HTTP vs HTTPS)

❌ Broken ``` Clerk Dashboard shows: https://yourdomain.com Your app redirects from: http://yourdomain.com → Mismatch = redirect loop ```

✅ Fixed ```typescript // next.config.js or vercel.json // Force HTTPS in production headers: { 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains' } ```

And in Clerk Dashboard, use only HTTPS for production URLs.

---

Still Broken? Check These Too

1. Cookie domain mismatch: If using yourdomain.com but accessing www.yourdomain.com, Clerk can't read the session cookie. Solution: Add both variants to Redirect URIs, or use wildcard domain in cookies if your Clerk plan supports it. *(Uncertain: wildcard behavior varies by Clerk version—check [official docs](https://clerk.com/docs))*

2. Stale build cache: Your Next.js build cached old middleware. Run rm -rf .next && npm run build and redeploy.

3. Custom auth wrapper around clerkMiddleware: If you wrapped clerkMiddleware() in another function, execution order breaks. Remove wrappers and call it directly. See [middleware integration guide](/?guide=clerk-middleware).

---

Quick Checklist

  • [ ] Clerk Dashboard lists your exact callback URL (protocol + domain + path)
  • [ ] clerkMiddleware() is the outermost wrapper in middleware.ts
  • [ ] No typos: https:// not http:// in production
  • [ ] Cleared browser cache and .next build folder
  • [ ] Deployed changes (Vercel auto-deploys on push)
  • [ ] 30+ seconds elapsed since Clerk config change
  • ---

    Still Seeing the Loop?

    Enable debug logging:

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

    export default function RootLayout({ children }) { return ( <ClerkProvider debug={process.env.NODE_ENV === 'development'} > {children} </ClerkProvider> ); } ```

    Check Network tab → filter by callback → see the exact redirect chain. Copy the full URL and verify it matches Clerk allowlist *exactly*.

    Official Clerk Docs: https://clerk.com/docs/authentication/redirects

    Related: [Clerk session validation errors](/?guide=clerk-session) | [Next.js middleware debugging](/?guide=nextjs-middleware)

    ---

    Found a different variation of this redirect loop? Drop it in the comments—2am bugs deserve 2am fixes.

    🔥 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