Middleware matcher leaves prefetched protected routes publicly accessible
0 reputation · 22 Jun 2024, 10:13 UTC
0 reputation · 22 Jun 2024, 10:13 UTC
In a Next.js App Router project (version 13 or later) using Middleware for centralized authentication, the goal is to guarantee that routes under a protected prefix such as /dashboard are never reachable without a valid session. The matcher configuration is intended to scope the security check to those paths, while the Edge Runtime restricts certain Node.js APIs during token verification.
The uncertainty lies in how the Next.js Router Cache and automatic prefetching interact with Middleware redirects. If a protected page is prefetched or cached on the client before authentication is checked, the redirect may not fire as expected, leaving the route accidentally public. Static assets under /public are also documented to bypass Middleware entirely, which complicates assumptions about blanket protection.
This raises an unresolved design decision about where to enforce the boundary. Should the matcher be narrowed to exclude prefetchable RSC requests, or should protection be duplicated in Server Components and route handlers? How does the documented behavior of the Router Cache affect the reliability of a Middleware-only redirect for protected App Router routes, and what verification steps confirm that no public path remains accessible?
34275 reputation · 22 Jun 2024, 21:52 UTC
Middleware is a perimeter defense, not a comprehensive security boundary. To guarantee that protected routes (e.g., /dashboard) are never accessible without a session, you must duplicate protection in Server Components or Layouts. Relying solely on the matcher is insufficient because the Next.js Router Cache can store React Server Component (RSC) payloads on the client, potentially displaying cached content even after a session expires or if a prefetch was handled inconsistently.
When a user hovers over a <Link>, Next.js triggers a prefetch request. This request passes through Middleware. If the user is authenticated during the prefetch, the RSC payload is stored in the client-side Router Cache. If the session expires after the prefetch but before the actual click, the client may render the cached page without triggering a new server request, bypassing the Middleware check for that specific navigation.
Furthermore, assets in the /public folder bypass Middleware entirely by design. If sensitive data is stored as static files, Middleware cannot protect them.
matcher to handle immediate redirects for unauthenticated users to avoid "flashes" of protected content.layout.tsx or specific page.tsx files within the protected directory. Since these are Server Components, they run on every full request and can trigger a redirect() if the session is invalid.RSC header, as these are the payloads being prefetched and cached.To confirm your security boundary is working, perform these three checks:
RSC=1) is intercepted by Middleware and returns the expected status code.matcher is correctly scoped.Diagnostic Detail Needed: Are you using a client-side session provider (like NextAuth.js SessionProvider) or a server-side cookie-based session? If using a client-side provider, the Router Cache behavior is more pronounced, necessitating a stricter server-side check in the Layout.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.