Clerk: redirect loop after authentication [2026 fix]

Clerk redirect loop caused by misconfigured CLERK_REDIRECT_URL or middleware order. Fix: set correct redirect URI in Clerk dashboard and reorder Next.js middleware.

Clerk: Redirect Loop After Authentication [2am Fix]

TL;DR

Cause: Your CLERK_REDIRECT_URL environment variable doesn't match your Clerk dashboard configuration, or your middleware is intercepting authenticated requests. Fix: Update CLERK_REDIRECT_URL to match your Clerk instance's redirect URIs and ensure middleware allows authenticated users through.

---

Exact Console Error Messages

``` Error: Invalid redirect_uri. The provided redirect_uri is not whitelisted. ```

``` [Clerk] The Clerk middleware encountered an error: Invalid redirect URI "http://localhost:3000/sign-in" - expected one of: ["http://localhost:3000"] ```

``` Infinite redirect loop detected. User authenticated but redirected back to /sign-in repeatedly. ```

``` (node:12845) UnhandledPromiseRejectionWarning: ClerkAPIResponseError: 403 Forbidden - redirect_uri not in allowed list ```

``` Warning: Clerk session created but middleware redirected to /sign-in before user reached protected route. ```

---

Broken Code vs. Fixed Code

Problem 1: Environment Variable Mismatch

BROKEN (.env.local): ```env CLERK_PUBLISHABLE_KEY=pk_test_... CLERK_SECRET_KEY=sk_test_... CLERK_REDIRECT_URL=http://localhost:3000/sign-in ```

FIXED (.env.local): ```env CLERK_PUBLISHABLE_KEY=pk_test_... CLERK_SECRET_KEY=sk_test_... CLERK_REDIRECT_URL=http://localhost:3000 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=/onboarding ```

Explanation: CLERK_REDIRECT_URL should be your base domain, NOT the sign-in path. The AFTER_SIGN_IN_URL controls where users go post-authentication.

---

Problem 2: Middleware Ordering

BROKEN (middleware.ts): ```typescript import { authMiddleware } from "@clerk/nextjs";

export const middleware = authMiddleware({ publicRoutes: ["/", "/pricing"], });

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

FIXED (middleware.ts): ```typescript import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";

const isPublicRoute = createRouteMatcher([ "/", "/pricing", "/sign-in(.*)", "/sign-up(.*)", "/api/public(.*)", ]);

export const middleware = clerkMiddleware((auth, req) => { if (!isPublicRoute(req)) { auth().protect(); } });

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

Explanation: Newer versions use clerkMiddleware with createRouteMatcher. Ensure sign-in/sign-up routes are explicitly marked as public to prevent the middleware from redirecting authenticated users back to sign-in.

---

Problem 3: Sign-In Page Configuration

BROKEN (app/sign-in/[[...index]]/page.tsx): ```typescript import { SignIn } from "@clerk/nextjs";

export default function SignInPage() { return <SignIn />; } ```

FIXED (app/sign-in/[[...index]]/page.tsx): ```typescript import { SignIn } from "@clerk/nextjs";

export default function SignInPage() { return ( <SignIn path="/sign-in" routing="path" signUpUrl="/sign-up" /> ); } ```

Explanation: Explicitly specify routing mode and URLs to prevent Clerk from using its default routing behavior, which may conflict with your middleware.

---

Verification Checklist

1. Clerk Dashboard: Navigate to Settings → API Keys. Verify CLERK_REDIRECT_URL value matches exactly what's in your .env.local. 2. Run locally: npm run dev and check browser console for specific 403 errors. 3. Clear cache: Hard-refresh (Cmd+Shift+R) and clear localhost cookies. 4. Check Next.js build: Run npm run build to catch configuration errors early.

---

Still Broken? Check These Too

1. [Clerk session not persisting across refreshes](/?guide=clerk-session-storage) — Verify your ClerkProvider wraps the entire app in layout.tsx. 2. [CORS errors with Clerk API calls](/?guide=clerk-cors-fix) — Ensure your domain is whitelisted in Clerk dashboard under Domains. 3. [Custom domain redirect loops](/?guide=clerk-custom-domain) — If using a custom domain, add it to Clerk settings AND your environment variables.

---

Version Notes

  • @clerk/nextjs >= 5.0: Uses clerkMiddleware() and createRouteMatcher(). Older middleware syntax will cause loops.
  • @clerk/nextjs < 5.0: Uses authMiddleware(). If you're on an older version, upgrade or consult the legacy docs.
  • Not certain about your version? Run npm list @clerk/nextjs to verify.

    ---

    Official Resources

  • [Clerk Next.js Documentation](https://clerk.com/docs/quickstarts/nextjs)
  • [Middleware Configuration Guide](https://clerk.com/docs/references/nextjs/clerk-middleware)
  • ---

    Found a different variation? Drop it in the comments.

    🔥 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