Fix: /pricing Now Accessible Without Authentication
Fix: /pricing Now Accessible Without Authentication
Version: 1.0.28
Overview
This release resolves a middleware configuration bug that was inadvertently blocking unauthenticated visitors from accessing the /pricing page. Unauthenticated users were being redirected to /sign-in when navigating to /pricing, making it impossible to evaluate plans or pricing without first signing up.
Background: How the Middleware Works
The platform uses Auth.js for authentication. In src/middleware.ts, the middleware is exported directly from Auth.js:
export { auth as middleware } from '@/auth';
This middleware intercepts every incoming request and redirects unauthenticated users to /sign-in by default. A matcher config is used to define which routes the middleware applies to — routes excluded from the matcher remain publicly accessible.
The Bug
The matcher pattern used a negative lookahead to exclude specific public paths:
export const config = {
matcher: ['/((?!api/auth|_next/static|_next/image|favicon.ico|sign-in|sign-up|$).*)'],
};
The root path ($) and auth routes (sign-in, sign-up) were correctly excluded. However, /pricing was absent from this list. As a result:
- A gym owner or prospect visiting
/pricingdirectly was immediately redirected to/sign-in. - The pricing page was effectively invisible to anyone without an existing account.
The Fix
pricing has been added to the negative lookahead exclusion list in the matcher:
export const config = {
matcher: ['/((?!api/auth|_next/static|_next/image|favicon.ico|sign-in|sign-up|pricing|$).*)'],
};
/pricing is now treated as a public route. Unauthenticated users can view pricing information freely, consistent with the intended pre-authentication experience.
Adding More Public Routes
If additional routes need to be publicly accessible in the future, there are two approaches:
Option 1: Extend the matcher exclusion list
Add the route name to the negative lookahead group:
// Before
/((?!api/auth|_next/static|_next/image|favicon.ico|sign-in|sign-up|pricing|$).*)
// After (example: also making /about public)
/((?!api/auth|_next/static|_next/image|favicon.ico|sign-in|sign-up|pricing|about|$).*)
Option 2: Use the Auth.js authorized callback
For more fine-grained control, configure public routes programmatically using the authorized callback in your Auth.js configuration:
export const { auth, handlers, signIn, signOut } = NextAuth({
callbacks: {
authorized({ auth, request }) {
const publicPaths = ['/', '/pricing', '/sign-in', '/sign-up'];
const isPublic = publicPaths.some(path =>
request.nextUrl.pathname.startsWith(path)
);
return isPublic || !!auth?.user;
},
},
});
This approach is recommended when the list of public routes grows or when route-matching logic becomes more complex.
Affected File
| File | Change |
|---|---|
src/middleware.ts | Added pricing to the matcher negative lookahead exclusion list |