Clerk: redirect loop after authentication [2026 fix]

Redirect loop after Clerk auth caused by misconfigured redirectUrl or missing middleware. Fix: verify CLERK_REDIRECT_URL env var and ensure middleware runs before auth routes.

Clerk: Redirect Loop After Authentication - Emergency Fix Guide

TL;DR

Problem: Your app authenticates successfully but immediately redirects back to the login page, creating an infinite loop. Fix: Verify your CLERK_REDIRECT_URL environment variable matches your actual domain and ensure Clerk middleware executes before your protected routes.

---

Exact Error Messages from Console

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

``` [Clerk] Redirect loop detected: redirectUrl does not match origin ```

``` Error: Invalid redirect URL. Expected origin to match CLERK_REDIRECT_URL, got http://localhost:3000 but config has https://example.com ```

``` (uncaught in promise) TypeError: Cannot read property 'redirectUrl' of undefined at _authenticateRequest ```

``` [Clerk] Auth session created but middleware skipped - redirect to /sign-in failed ```

``` WARN: afterAuthUrl not reachable. Infinite redirect detected. Fallback to /dashboard ```

---

Broken Code vs. Exact Fix

Issue #1: Wrong Environment Variable

BROKEN: ```javascript // .env.local (WRONG - includes /auth path) CLERK_REDIRECT_URL=https://example.com/auth CLERK_PUBLISHABLE_KEY=pk_live_... CLERK_SECRET_KEY=sk_live_... ```

FIXED: ```javascript // .env.local (CORRECT - base domain only) CLERK_REDIRECT_URL=https://example.com CLERK_PUBLISHABLE_KEY=pk_live_... CLERK_SECRET_KEY=sk_live_... ```

---

Issue #2: Middleware Not Running on Protected Routes

BROKEN (Next.js App Router): ```javascript // middleware.ts - placed incorrectly or not configured import { auth } from '@clerk/nextjs/server';

export default async function middleware(request) { // This only runs on public routes! return NextResponse.next(); }

export const config = { matcher: ['/public/:path*'] // TOO RESTRICTIVE }; ```

FIXED: ```javascript // middleware.ts - correct configuration import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';

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

export default clerkMiddleware((auth, req) => { if (isProtectedRoute(req)) { auth().protect(); } });

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

---

Issue #3: ClerkProvider afterSignInUrl Mismatch

BROKEN: ```javascript // app.tsx or root layout <ClerkProvider afterSignInUrl="/dashboard" afterSignUpUrl="/onboarding" // Missing signInUrl causes redirect loop fallback > <App /> </ClerkProvider> ```

FIXED: ```javascript // app.tsx - explicit URLs that match your app structure <ClerkProvider publishableKey={process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY} signInUrl="/sign-in" signUpUrl="/sign-up" afterSignInUrl="/dashboard" afterSignUpUrl="/onboarding" > <App /> </ClerkProvider> ```

---

Root Cause Analysis

Redirect loops occur when:

1. Domain mismatch: Your CLERK_REDIRECT_URL points to a different domain than where your app is running 2. Middleware skipped: Clerk's authentication middleware doesn't execute before route handlers, leaving the session unverified 3. Infinite afterSignInUrl chain: Your afterSignInUrl redirects back to /sign-in instead of a protected page 4. Missing origin header: Deployed apps sometimes fail to pass correct origin in requests

---

Still Broken? Check These Too

1. Cookie Domain Configuration

If you have multiple subdomains, ensure cookies are set correctly: ```javascript // In Clerk Dashboard → Advanced → Cookie Settings // Set to: .example.com (with leading dot for subdomains) ```

2. Development vs. Production Environment Variables

Verify your deployed environment actually has CLERK_REDIRECT_URL set: ```bash

Vercel example

vercel env pull .env.local grep CLERK_REDIRECT_URL .env.local ```

3. Auth State Hydration Race Condition

Add defensive checks in your protected components: ```javascript const DashboardPage = () => { const { isLoaded, userId } = useAuth(); if (!isLoaded) return <LoadingSpinner />; // Wait for hydration if (!userId) return <Navigate to="/sign-in" />; // Explicit redirect return <Dashboard />; }; ```

---

Quick Verification Checklist

  • [ ] CLERK_REDIRECT_URL matches your production domain exactly (no paths, no trailing slash)
  • [ ] Middleware file is in src/middleware.ts (Next.js) or correct location for your framework
  • [ ] clerkMiddleware() is imported from @clerk/nextjs/server, not deprecated @clerk/nextjs
  • [ ] All protected routes are listed in createRouteMatcher()
  • [ ] afterSignInUrl points to a route that exists and doesn't redirect back to auth
  • [ ] Cookies are enabled in your browser (check DevTools → Application → Cookies)
  • [ ] No custom interceptors are modifying redirect responses
  • ---

    Official Documentation

    Refer to the [Clerk Next.js Setup Guide](https://clerk.com/docs/quickstarts/nextjs) and [Middleware Configuration](https://clerk.com/docs/references/nextjs/clerk-middleware) for your specific framework version.

    Also see our related guides: [Clerk authentication fails silently](/?guide=clerk-silent-fail) [Session persistence issues in production](/?guide=clerk-session-prod)

    ---

    Found a different variation? Drop it in the comments

    If you encountered a redirect loop with a different root cause or you're using Express, Remix, or another framework, please share your error messages and setup in the comments below. Community fixes help everyone at 2am! 🚀

    🔥 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