Currently, I am utilizing the App Router in nextjs14 with stacked middleware to handle localization and authentication. The issue arises when trying to access auth in the Request object while using next-auth v5 for authentication.
Interestingly, the code functions perfectly in middleware.ts without any additional middleware for localization. However, as soon as other middlewares are added, request.auth becomes undefined and triggers a TypeScript error stating "Property 'auth' does not exist on type 'NextRequest'.ts(2339)".
The working code snippet in middleware.ts looks like this:
import NextAuth from "next-auth";
import authConfig from "@/auth.config";
import {
DEFAULT_LOGIN_REDIRECT,
apiAuthPrefix,
authRoutes,
publicRoutes
} from "@/routes";
const { auth } = NextAuth(authConfig);
export default auth((req) => {
// Middleware logic here
const { nextUrl } = req;
const isLoggedIn = !!req.auth;
console.log("req.auth: ", req.auth);
const isApiAuthRoute = nextUrl.pathname.startsWith(apiAuthPrefix);
const isPublicRoute = publicRoutes.includes(nextUrl.pathname);
const isAuthRoute = authRoutes.includes(nextUrl.pathname);
console.log({
url: nextUrl.pathname,
isApiAuthRoute: isApiAuthRoute,
isAuthRoute: isAuthRoute,
isPublicRoute: isPublicRoute,
isLoggedIn: isLoggedIn,
});
if (isApiAuthRoute) {
return null;
}
if (isAuthRoute) {
if (isLoggedIn) {
return Response.redirect(new URL(DEFAULT_LOGIN_REDIRECT, nextUrl));
}
return null;
}
if (!isLoggedIn && !isPublicRoute && !isAuthRoute) {
return Response.redirect(new URL("/en/login", nextUrl));
// return null;
}
return null;
})
export const config = {
matcher: ["/((?!.+\\.[\\w]+$|_next).*)", "/", "/(api|trpc)(.*)"],
};
However, the following code in middlewares/authMiddleware.ts encounters issues:
import {
NextFetchEvent,
NextRequest,
NextResponse
} from "next/server";
import { MiddlewareFactory } from "@/lib/definitions";
import NextAuth from "next-auth";
import authConfig from "@/auth.config";
import {
DEFAULT_LOGIN_REDIRECT,
apiAuthPrefix,
authRoutes,
publicRoutes
} from "@/routes";
const { auth } = NextAuth(authConfig);
function getSearchParam(param: string, url: any) {
return url.searchParams.get(param);
}
export const authMiddleware: MiddlewareFactory = (next) => {
return async(request: NextRequest, _next: NextFetchEvent) => {
const pathname = request.nextUrl.pathname;
if (["/"]?.some((path) => pathname.startsWith(path))) {
// Middleware logic here
const { nextUrl } = request;
const isLoggedIn = !!request.auth;
console.log("request.auth: ", request);
const isApiAuthRoute = nextUrl.pathname.startsWith(apiAuthPrefix);
const isPublicRoute = publicRoutes.includes(nextUrl.pathname);
const isAuthRoute = authRoutes.includes(nextUrl.pathname);
console.log({
url: nextUrl.pathname,
isApiAuthRoute: isApiAuthRoute,
isAuthRoute: isAuthRoute,
isPublicRoute: isPublicRoute,
isLoggedIn: isLoggedIn,
});
if (isApiAuthRoute) {
return null;
}
if (isAuthRoute) {
if (isLoggedIn) {
return Response.redirect(new URL(DEFAULT_LOGIN_REDIRECT, nextUrl));
}
return null;
}
if (!isLoggedIn && !isPublicRoute && !isAuthRoute) {
return Response.redirect(new URL("/en/login", nextUrl));
// return null;
}
return null;
// End
}
return next(request, _next);
};
};
An attempt was made to add the following code:
import { NextRequest as OriginalNextRequest } from "next/server";
declare global {
declare interface NextRequest extends OriginalNextRequest {
auth: any
}
}
This modification was made in global.d.ts at the root of my project, using it instead of calling NextRequest from next/server. Unfortunately, an error occurred:
Type '(next: NextMiddleware) => (request: NextRequest, _next: NextFetchEvent) => Promise<NextMiddlewareResult>' is not assignable to type 'MiddlewareFactory'.
Type '(request: NextRequest, _next: NextFetchEvent) => Promise<NextMiddlewareResult>' is not assignable to type 'NextMiddleware'.
Types of parameters 'request' and 'request' are incompatible.
Property 'auth' is missing in type 'import("p:/cts-final/frontend/node_modules/next/dist/server/web/spec-extension/request").NextRequest' but required in type 'NextRequest'.ts(2322)
global.d.ts(5, 9): 'auth' is declared here.
I am seeking guidance on how to extend NextRequest to include the auth property, assuming that is the appropriate solution?