Clerk: redirect loop after authentication [2026 fix]

Redirect loop after Clerk login caused by misconfigured redirect URIs or stale middleware. Clear your allowed origins and verify callback URLs match exactly.

Clerk: Redirect Loop After Authentication - Emergency Fix

TL;DR

Cause: Your Clerk redirect URIs don't match your actual app URLs (including protocol, domain, and port). Fix: Update your Clerk dashboard allowed origins to match your app's exact callback URL.

---

Exact Console Error Messages

Watch for these in your browser console, server logs, and Clerk logs:

``` 1. "Error: redirect_uri_mismatch: The redirect_uri does not match any of the allowed URIs"

2. "GET /api/auth/callback?code=xyz - 307 Temporary Redirect" (repeating)

3. "Warning: useAuth() returned null; user is not authenticated but callback succeeded"

4. "ReferenceError: __clerk_internal_redirect is not defined"

5. "POST https://[your-instance].clerk.accounts.com/oauth/authorize - 400 Bad Request" ```

The 307 loop (see error #2) is the smoking gun—your app keeps redirecting to Clerk, which redirects back, creating an infinite loop.

---

Broken Code vs. Exact Fix

❌ BROKEN: Mismatched Redirect URIs

Dashboard Configuration: ``` Allowed Origins: https://myapp.com Redirect URLs: https://myapp.com/auth/callback ```

Your code (middleware): ```javascript // nextjs/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(); // Breaks if callback URL is wrong } }); ```

Production app running on: https://myapp.com:3000 or http://localhost:3000 during testing

Mismatch! Dashboard says https://myapp.com but your app is https://myapp.com:3000

---

✅ FIXED: Exact URI Match

Step 1: Update Clerk Dashboard

Go to: Clerk Dashboard → Settings → Allowed Origins & Redirect URLs

``` Allowed Origins: - https://myapp.com - https://myapp.com:3000 - http://localhost:3000

Redirect URLs: - https://myapp.com/api/auth/callback - https://myapp.com:3000/api/auth/callback - http://localhost:3000/api/auth/callback ```

Step 2: Verify your environment variables match

```bash

.env.local

NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_... CLERK_SECRET_KEY=sk_live_... 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 ```

Step 3: Keep your middleware simple (unchanged)

```javascript // nextjs/middleware.ts - No changes needed if config is correct import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';

const isPublicRoute = createRouteMatcher([ '/', '/sign-in(.*)', '/sign-up(.*)', '/api/webhook(.*)', // Clerk webhooks must be public ]);

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

export const config = { matcher: [ '/((?!_next|static|.*\\..*|favicon).*)', ], }; ```

Step 4: Clear browser cache and restart dev server

```bash

Kill your dev server

npm run dev (or yarn dev, etc.)

```

Why this works: Clerk compares the redirect_uri parameter from your sign-in button against the dashboard whitelist byte-for-byte. Port numbers, protocols (http vs https), and subdomains all matter.

---

Still Broken? Check These Too

Issue #1: Stale middleware cache

  • Clear .next/ folder and node_modules/.cache
  • Restart dev server completely (don't rely on hot reload)
  • Clear browser cookies and local storage for your domain
  • Issue #2: Wrong callback route in your sign-in component

  • If you're using a custom <SignIn /> component, check redirectUrl prop
  • Ensure it matches NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL
  • Example: <SignIn redirectUrl="/dashboard" /> must point to an authenticated route
  • Issue #3: Webhook signature validation failing silently

  • Clerk webhooks trigger sign-out on secret mismatch
  • Verify CLERK_WEBHOOK_SECRET in environment
  • Check Clerk dashboard → Webhooks → endpoint URL matches your /api/webhooks/clerk route
  • See [guide on Clerk webhooks](/?guide=clerk-webhooks) for details
  • ---

    Version Uncertainty Note

    This guide covers Clerk SDK v4.x and v5.x (2024-2026). If you're on v3 or earlier, callback URL configuration differs slightly—check your installed version with npm list @clerk/nextjs. The redirect loop symptom remains consistent across versions, but the configuration UI location may differ in older dashboards.

    ---

    External Reference

    📖 [Clerk Official Docs: Redirect URIs](https://clerk.com/docs/deployments/configure-allowed-origins)

    🔗 [Related: Set up sign-in/sign-up routes](/?guide=clerk-setup)

    🔗 [Related: Clerk session management](/?guide=clerk-sessions)

    ---

    Found a different variation? Drop it in the comments — if your redirect loop has a different root cause (e.g., custom domain routing, reverse proxy issues, or regional deployment quirks), share it below to help other developers 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