Fixing the Middleware Matcher Root Path Bug
Fixing the Middleware Matcher Root Path Bug
Release: v1.0.51
Background
Sidekick uses Auth.js (NextAuth v5) middleware in src/middleware.ts to gate access to authenticated routes. The middleware is selectively applied using a Next.js matcher pattern — routes matching the pattern are intercepted, while public routes (like the landing page, sign-in, and sign-up pages) are intended to be excluded.
The Bug
The original matcher pattern was:
export const config = {
matcher: ['/((?!api/auth|_next/static|_next/image|favicon.ico|sign-in|sign-up|$).*)'],
};
The intent of $ at the end of the negative lookahead group was to exclude the root path / from middleware processing. However, within a lookahead group in this context, $ is treated as a literal character — it matches a dollar sign in the URL, not the end of the string. This means the root path / was not excluded and Auth.js middleware ran on every request to /.
Why It Didn't Break Anything (But Still Mattered)
Auth.js does not redirect unauthenticated users away from public pages — it simply resolves the session and passes the request through. So the landing page continued to render correctly. However:
- Every request to
/incurred the full Auth.js middleware overhead (session token validation, cookie parsing, etc.). - It was a subtle correctness bug that could cause unexpected behaviour if middleware logic became more strict in future.
- It made the middleware config misleading — developers reading the pattern would expect
/to be excluded.
The Fix
The matcher has been updated to explicitly list public routes that should bypass the middleware, and auth checking for public routes is delegated to the page level:
export const config = {
matcher: ['/((?!api/auth|_next/static|_next/image|favicon.ico|sign-in|sign-up|pricing).*)'],
};
Key changes:
- The ambiguous
$lookahead entry has been removed. - Public marketing/landing routes (e.g.
pricing) are excluded directly in the matcher. - The root path
/and other public routes are handled by page-level auth checks where needed, keeping the middleware focused solely on protecting authenticated surfaces.
Guidance for Custom Deployments
If you are running a self-hosted or customised version of Sidekick and have extended src/middleware.ts, audit your matcher pattern for the same issue:
- Do not rely on
$inside a negative lookahead within a Next.js matcher string to match end-of-string — use explicit path segments instead. - List every public route you want to exclude from middleware in the lookahead group.
- Use page-level session checks (e.g.
getServerSession()orauth()) for public pages that have conditional authenticated UI, rather than relying on the middleware to short-circuit.
Testing Your Matcher
You can verify which paths your matcher covers using a regex tester with the raw pattern (strip the surrounding /( and )):
(?!api/auth|_next/static|_next/image|favicon.ico|sign-in|sign-up|pricing).*
Test against /, /dashboard, /api/auth/session, /sign-in, and any other routes critical to your deployment.