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