Next.js Middleware Missing an Exclusion Forces Login
This article may contain affiliate links. Its content is not affected by advertising.
In short
Because Next.js middleware (Proxy) subjects every route to an auth check by default, a newly added no-login route keeps redirecting to /login until you add it to the exclusion condition yourself.
Conclusion
Next.js middleware (renamed Proxy in Next.js 16) applies whatever condition you write to every route by default. So when you later add a “no login required” route, nothing redirects it away from /login unless you explicitly add that exclusion to the middleware’s own auth condition. Here, a partner-facing public share link (/p/[token], used to view and download invoices and quotes) had been left out of that exclusion.
Symptom
The public share link /p/[token] exists so partners without a login account can view invoices and quotes — it’s meant to work without logging in. Instead, opening it redirected straight to /login before any content rendered, so partners were asked to log in just to see a document that was never supposed to require one.
Cause
Every Next.js request passes through the proxy() function in src/proxy.ts, which checks the Supabase session and redirects to /login when the user isn’t authenticated.
// src/proxy.ts:44-52 (before)
const path = request.nextUrl.pathname;
const isLogin = path === "/login";
if (!isAuthed && !isLogin) {
const url = request.nextUrl.clone();
url.pathname = "/login";
url.search = "";
return NextResponse.redirect(url);
}
This condition redirects every path except /login itself whenever the user is unauthenticated. The public share route /p/[token] gets no special treatment: since isLogin evaluates to false for it, it falls straight into this branch.
The screen that handles /p/[token] — verifying the token and rendering the document — was already implemented. What was missing was a line in the middleware’s own condition, which runs before that screen, exempting this public route. Because the feature’s implementation and the blanket auth check live in separate files, a working feature can still get swept into /login unless the middleware-side exclusion is added separately.
The fix
Add isPublic, which checks whether path starts with /p/, directly into the auth condition.
// src/proxy.ts:44-53 (after)
const path = request.nextUrl.pathname;
const isLogin = path === "/login";
// External public link (/p/[token]): no login required. Partners view/download invoices and quotes.
const isPublic = path.startsWith("/p/");
if (!isAuthed && !isLogin && !isPublic) {
const url = request.nextUrl.clone();
url.pathname = "/login";
url.search = "";
return NextResponse.redirect(url);
}
One line, path.startsWith("/p/"), was enough. The key decision was putting that check inside the middleware’s own condition, which every request passes through, rather than in the /p/[token] screen itself — so any future page added under /p/ needs no individual handling.
Making it less likely to recur
This bug was fixed in a single commit, and nothing in the commit history that documents the fix adds a new rule or checklist to prevent the next occurrence. It got fixed because someone noticed, not because a mechanism now catches the next gap.
Structurally, this kind of gap tends to appear when the place that enforces auth for everything (middleware) and the place that implements a no-login feature (each page) live in separate files. Building a new no-login route feels complete once the page itself works, which makes it easy to miss that you also need to go back to proxy.ts and add the exclusion there. In this case, the public share link’s screen was already working fine — only the auth-side condition had failed to catch up.
Frequently asked questions
Q1How do you exclude one path from auth in Next.js middleware (Proxy)?
Read request.nextUrl.pathname and add the exclusion directly inside the auth-check if statement. Here we added `&& !isPublic` (isPublic = path.startsWith("/p/")) to the existing `!isAuthed && !isLogin` condition, exempting only links under /p/. It only works inside that if statement.
Q2What was the actual impact of this bug?
A logged-out business partner opening a public share link (/p/[token]) was redirected to /login before seeing any content. Invoices and quotes were handed out as links meant to need no login, but the link demanded one first.
Q3The feature existed — why was only the exclusion missing?
The screen rendering /p/[token] (verify token, show document) was already built. The problem was the middleware's condition, which runs first and requires auth on every route. Feature and auth check live in separate files, so a working feature can still get blocked by middleware.
Environment verified
- Next.js 16.2.7 (App Router; Middleware was renamed Proxy in Next.js 16)
- Occurred and fixed same day, 2026-06-05
What this article is based on
- TypeScript file lines 44-52commit 3731348
- TypeScript file lines 44-53commit 4fb9321
Every claim in this article comes from the records above. The repositories we operate are private so we cannot link to them, but which file, which lines, and at which commit we read them is recorded for every article. Nothing here is written from guesswork.