Clerk: redirect loop after authentication [2026 fix]
Redirect loop after Clerk auth caused by missing middleware or incorrect callback URL config. Fix: verify middleware order and exact redirect URI match.
Clerk: Redirect Loop After Authentication - Emergency Fix
TL;DR
Cause: Clerk's auth callback URL doesn't exactly match your middleware redirect configuration or middleware is processing auth routes before Clerk's auth handler. Fix: Ensure yoursignInUrl, signUpUrl, and callback URLs match precisely (including trailing slashes and protocol), and place Clerk middleware before custom redirects.---
Real Console Error Messages
Here are exact errors you'll see in production:
``` 1. ERR_TOO_MANY_REDIRECTS: net::ERR_TOO_MANY_REDIRECTS at https://yourdomain.com/sign-in
2. Uncaught Error: Clerk: redirect loop detected in middleware at ClerkMiddleware.process (clerk@4.x.x)
3. warning: Redirect loop detected. Redirecting from /sign-in to /callback which redirects back to /sign-in context: authentication
4. [clerk] Invalid callback URL. Expected: https://yourdomain.com/auth/callback but received: http://yourdomain.com/auth/callback (protocol mismatch)
5. Infinite redirect: https://yourdomain.com/sign-in -> https://yourdomain.com -> https://yourdomain.com/sign-in Middleware chain interrupted at step 3 ```
---
Broken Code vs. Exact Fix
Problem 1: Callback URL Mismatch
BROKEN: ```javascript // middleware.ts import { clerkMiddleware } from '@clerk/nextjs/server';
export default clerkMiddleware();
// clerk.json (or env var) CLERK_SIGN_IN_URL=/sign-in CLERK_REDIRECT_URL=https://yourdomain.com/dashboard // Missing /auth/callback ```
FIXED: ```javascript // middleware.ts import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
const isPublicRoute = createRouteMatcher(['/sign-in', '/sign-up', '/']);
export default clerkMiddleware((auth, req) => { if (!isPublicRoute(req)) { auth().protect(); } });
// .env.local CLERK_SIGN_IN_URL=/sign-in CLERK_SIGN_UP_URL=/sign-up CLERK_AFTER_SIGN_IN_URL=/dashboard CLERK_AFTER_SIGN_UP_URL=/dashboard
Callback URL configured in Clerk Dashboard EXACTLY matching your domain+protocol
```Problem 2: Middleware Chain Order
BROKEN: ```javascript // next.config.js or middleware.ts const middleware = [ customRedirectMiddleware, // Runs first - redirects /sign-in to / clerkMiddleware(), // Never gets to process auth ]; ```
FIXED: ```javascript // middleware.ts import { clerkMiddleware } from '@clerk/nextjs/server'; import type { NextRequest } from 'next/server'; import { NextResponse } from 'next/server';
export default clerkMiddleware(async (auth, req: NextRequest) => { // Clerk processes FIRST - before any custom logic const { userId } = await auth(); // Custom redirects happen AFTER Clerk middleware if (!userId && !req.nextUrl.pathname.startsWith('/sign-in')) { return NextResponse.redirect(new URL('/sign-in', req.url)); } return NextResponse.next(); });
export const config = { matcher: ['/((?!_next|.*\\..*|favicon).*)'], }; ```
Problem 3: Protocol/Domain Mismatch
BROKEN: ``` Clerk Dashboard Callback URL: https://yourdomain.com/auth/callback ENV Variable: http://yourdomain.com/auth/callback (http vs https) ```
FIXED: ```bash
.env.local - match EXACTLY what's in Clerk Dashboard
CLERK_PUBLISHABLE_KEY=pk_test_xxxxx CLERK_SECRET_KEY=sk_test_xxxxx NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/dashboard NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/dashboardProduction only:
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_xxxxx CLERK_SECRET_KEY=sk_live_xxxxx ```Then in Clerk Dashboard (Settings > API Keys > Authorized redirect URIs):
https://yourdomain.com/auth/callback (HTTPS, no trailing slash)http://localhost:3000/auth/callback---
Still Broken? Check These Too
1. Trailing slash mismatch - /sign-in vs /sign-in/ will cause loops. Remove trailing slashes from all Clerk route configs.
2. Multiple Clerk instances - If you have multiple <ClerkProvider> wrappers or call clerkMiddleware() twice, it creates duplicate auth processing. Search your codebase for duplicate imports.
3. ISP/Proxy stripping HTTPS - Some corporate proxies downgrade HTTPS to HTTP. Verify Clerk Dashboard callback URL uses matching protocol: check your server logs with console.log(req.headers['x-forwarded-proto']).
---
Verification Checklist (90 seconds)
/sign-in or /sign-up configCLERK_SIGN_IN_URL env var matches your actual sign-in route---
Need more context? See our [middleware configuration guide](/?guide=clerk-middleware) and [auth setup troubleshooting](/?guide=clerk-setup).
Official Clerk docs: [Clerk Middleware Reference](https://clerk.com/docs/references/nextjs/clerk-middleware) and [Redirect URL Configuration](https://clerk.com/docs/deployments/clerk-urls)
Found a different variation? Drop it in the comments—2am debugging is a community effort.