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