Home/Tools/Next.js 15 Middleware Architect
100% Free Developer Utility

Next.js 15 Middleware & Route Guard Architect

AI assistants constantly mangle middleware matcher regexes, accidentally leaving sensitive API routes unprotected or running Edge middleware on every single image fetch. Generate a production-ready middleware.ts in seconds.

Select Auth Stack

The Webhook Matcher Disaster

If your middleware runs on Stripe or Resend webhooks and redirects unauthenticated requests to /login with an HTTP 307 redirect, Stripe will treat the response as a failed delivery and eventually disable your webhook endpoint in production.

Our generated middleware explicitly bypasses webhook paths so signatures remain intact.

middleware.ts
import { createServerClient } from '@supabase/ssr';
import { NextResponse, type NextRequest } from 'next/server';

export async function middleware(request: NextRequest) {
  let response = NextResponse.next({
    request: {
      headers: request.headers,
    },
  });

  const pathname = request.nextUrl.pathname;

  // 1. Always bypass webhooks (preserves raw signature buffer)
  if (pathname.startsWith('/api/webhooks')) {
    return response;
  }

  const supabase = createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll() {
          return request.cookies.getAll();
        },
        setAll(cookiesToSet) {
          cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value));
          response = NextResponse.next({
            request,
          });
          cookiesToSet.forEach(({ name, value, options }) =>
            response.cookies.set(name, value, options)
          );
        },
      },
    }
  );

  // Refresh auth session
  const { data: { user } } = await supabase.auth.getUser();

  // 2. Protect authenticated paths
  const isProtected = ["/dashboard","/settings","/api/user"].some((path) => pathname.startsWith(path));
  if (isProtected && !user) {
    const redirectUrl = request.nextUrl.clone();
    redirectUrl.pathname = '/login';
    redirectUrl.searchParams.set('redirect', pathname);
    return NextResponse.redirect(redirectUrl);
  }

  // 3. Redirect logged-in users away from login/signup
  const isAuthPage = pathname === '/login' || pathname === '/signup';
  if (isAuthPage && user) {
    const redirectUrl = request.nextUrl.clone();
    redirectUrl.pathname = '/dashboard';
    return NextResponse.redirect(redirectUrl);
  }

  return response;
}

export const config = {
  matcher: [
    /*
     * Match all request paths except:
     * - _next/static (static files)
     * - _next/image (image optimization files)
     * - favicon.ico (favicon file)
     * - images, png, svg, webp, jpg
     */
    '/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
  ],
};
Want your actual route protections tested?

Middleware route coverage is Check 11 in our 108 launch criteria. The Founder Pass ($15 one-time) verifies that your private API handlers and Server Actions cannot be bypassed even if someone hits them directly.