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