Allow middleware matcher to match route group #44635
Replies: 37 comments
-
In our use-case, something like that would allow extracting authentication logic into separate packages for easier re-use. Also, would have been wonderful, to be able to render custom components as pages. E.g. imagine, you're adding |
Beta Was this translation helpful? Give feedback.
-
Yes, this would make it so easy to manage middleware matchers.. |
Beta Was this translation helpful? Give feedback.
-
Is this feature available? |
Beta Was this translation helpful? Give feedback.
-
It seems that, at the moment, specifying paths to be excluded and returning null is not the ideal solution, but it appears to be the best option available. // middleware.ts
const unauthenticatedRoutes = ['/login','signup']
const isUnauthenticated = unauthenticatedRoutes.includes(nextUrl.pathname);
if (isUnauthenticated) return null; |
Beta Was this translation helpful? Give feedback.
-
I was gonna open this exact issue. For the readers, this is how I currently do the implementation
example of import { NextRequestWithAuth, withAuth } from "next-auth/middleware";
import { NextResponse } from "next/server";
const roleAccessConfig = {
admin: ["/"],
tutor: ["/tutor", "/onboarding"],
student: ["/student", "/onboarding"],
family: ["/family", "/onboarding"],
user: ["/onboarding"],
};
function authMiddleware(req: NextRequestWithAuth) {
// Role based access control
const userRole = req.nextauth.token?.user?.role;
const pathName = req.nextUrl.pathname;
if (userRole) {
// Check if the user's role has access to the current page
const allowedRoutes = roleAccessConfig[userRole as keyof typeof roleAccessConfig];
if (!allowedRoutes || !allowedRoutes.some((route) => pathName.includes(route))) {
return NextResponse.redirect(new URL("/unauthorized", req.nextUrl));
}
}
}
export default withAuth(authMiddleware, {
callbacks: {
authorized: async ({ token }) => {
return !!token;
},
},
});
// config to exclude auth pages from being protected
export const config = {
matcher: ["/dashboard/:path*", "/admin/:path*"],
}; |
Beta Was this translation helpful? Give feedback.
-
+1 I am currently using a similar workaround/implementation as anindosarker. The possibility to access the group in the middleware would have made the configuration much clearer. |
Beta Was this translation helpful? Give feedback.
-
Would it maybe even be stronger to enable multiple middlewares in a file-system based nested manner? This way, not only route groups are added, but several more things? |
Beta Was this translation helpful? Give feedback.
-
Lee Robinson pointed towards experimental interceptors #70961 these might answer at least part of this discussion? |
Beta Was this translation helpful? Give feedback.
-
This seems like a major miss. How can we not specify route groups in the middleware to cover all paths and pages in a route group. Currently, the only way to make this work is to specify each path individually which is not scalable. At first, I thought I could create a middleware group for each route group and just realized that it wasn't working because you can only have one middleware in the root. There are going to be a lot of developers who think it's best to use root paths versus sub-directory based paths like |
Beta Was this translation helpful? Give feedback.
-
You could drop middleware and use a Layout server component in the root of your route group to perform functions that the middleware would otherwise perform. That way you have granular control over all groups. // /app/(protected)/layout.tsx
import { getAuthCurrentUser } from "@/utils/utils";
import { headers } from "next/headers";
import { redirect } from "next/navigation";
export default async function ProtectedLayout({
children,
}: {
children: React.ReactNode;
}) {
const user = await getAuthCurrentUser();
// Get the current path from headers
const headersList = headers();
const currentPath = headersList.get("x-current-path") || "/";
if (!user) {
redirect(`/signup?source=${currentPath}`);
}
return <>{children}</>;
} To make this work, I do have a middleware to add "x-current-path" to my headers: // middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
const headers = new Headers(request.headers);
headers.set("x-current-path", request.nextUrl.pathname);
return NextResponse.next({ headers });
}
export const config = {
matcher: [
"/((?!api|_next/static|_next/image|favicon.ico).*)",
],
}; It would be easier if we could do it directly in the middleware, but this is a good workaround. Granted it only showcases protecting route groups, but it can be adapted to most use cases. |
Beta Was this translation helpful? Give feedback.
-
Describe the feature you'd like to request
It would be nice if we could configure the middleware matcher to match an entire route group so that we can have greater flexibility with middleware.
The use cases for this could range from authorization, authentication, feature flags, etc.
Describe the solution you'd like
Given the following example file structure
Allow some kind of pattern matching in the middleware config
In this example, I could redirect the user to the login page if they are not authenticated via the middleware.
Describe alternatives you've considered
I have considered adding a nested layout under the (authenticated) route group, however, adding a layout for the purpose of performing logic on the request seems like something that is better fitted in the middleware. Since middleware executes before the request is processed, it might result in a smoother transition to have the logic performed there.
Beta Was this translation helpful? Give feedback.
All reactions