Chaining multiple middleware (next-auth and multi locale) in Next.js 13
Answered
West African Crocodile posted this in #help-forum
West African CrocodileOP
I want to implement multiple middleware in my Next.js app. Here's my
withLocale.ts file:import { NextResponse, NextRequest } from 'next/server';
import acceptLanguage from 'accept-language';
import { fallbackLng, languages } from '@/app/i18n/settings';
import { PATH_LOGIN } from '@/config/path';
acceptLanguage.languages(languages);
export const config = {
matcher: [
'/((?!api|_next/static|_next/image|assets|favicon.ico|sw.js|manifest.json).*)',
],
};
const cookieName = 'i18next';
export function withLocale(req: NextRequest) {
if (
req.nextUrl.pathname.indexOf('icon') > -1 ||
req.nextUrl.pathname.indexOf('chrome') > -1
)
return NextResponse.next();
let lng: string | null = '';
if (req.cookies.has(cookieName))
lng = acceptLanguage.get(req.cookies.get(cookieName)?.value);
if (!lng) lng = acceptLanguage.get(req.headers.get('Accept-Language'));
if (!lng) lng = fallbackLng;
// Exclude specific routes from redirection
const excludedRoutes = ['/welcome', PATH_LOGIN];
// Redirect if lng in path is not supported
if (
!languages.some((loc) => req.nextUrl.pathname.startsWith(`/${loc}`)) &&
!req.nextUrl.pathname.startsWith('/_next') &&
req.nextUrl.pathname !== '/' &&
!excludedRoutes.includes(req.nextUrl.pathname)
) {
return NextResponse.redirect(
new URL(`/${lng}${req.nextUrl.pathname}`, req.url),
);
}
if (req.headers.has('referer')) {
const refererUrl = new URL(req.headers.get('referer')!);
const lngInReferer = languages.find((l) =>
refererUrl.pathname.startsWith(`/${l}`),
);
const response = NextResponse.next();
if (lngInReferer) response.cookies.set(cookieName, lngInReferer);
return response;
}
return NextResponse.next();
}
export default withLocale;Answered by Clown
Hmm... i haven't had to personally do this so im not 100% sure that there is any other way than conditional checking when you want different middlewares functionality for different paths:
https://nextjs.org/docs/pages/building-your-application/routing/middleware#conditional-statements
https://nextjs.org/docs/pages/building-your-application/routing/middleware#conditional-statements
8 Replies
West African CrocodileOP
and here is my
That's how I got them chaining. But initially, I got
Another thing is that I have multiple configs for matching the path. I've read post about using a single file for both middleware but nothing worked for me. I think it's because they have a different structure, so we can't "loop" through them (or something like that). I'm using Next-Auth and I have not seen examples of multiple middleware with it.
My Next.js version is
[1]: https://github.com/nextauthjs/next-auth-example/blob/main/middleware.ts
middleware.ts file:import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { withAuth } from "next-auth/middleware"
import withLocale from "@/app/middlewares/withLocale";
export default async function middleware(req: NextRequest) {
const response = await withLocale(req);
console.log('response ====> ', response);
if (response.status === 200) {
console.log("response === NextResponse.next()");
// If the withLocale middleware didn't redirect or replace the response, run withAuth
return await withAuth({
callbacks: {
authorized({ req, token }) {
// `/admin` requires admin role
if (req.nextUrl.pathname === "/admin") {
return token?.userRole === "admin";
}
// `/me` only requires the user to be logged in
return !!token;
},
},
})
} else {
// If the withLocale middleware did something with the response, just return that
return response;
}
}
export const config = { matcher: ["/(en|es|ru)/(chat|intake-form|home|settings|stories|words)"] }That's how I got them chaining. But initially, I got
withAuth from [here][1].Another thing is that I have multiple configs for matching the path. I've read post about using a single file for both middleware but nothing worked for me. I think it's because they have a different structure, so we can't "loop" through them (or something like that). I'm using Next-Auth and I have not seen examples of multiple middleware with it.
My Next.js version is
13.4.16.[1]: https://github.com/nextauthjs/next-auth-example/blob/main/middleware.ts
@West African Crocodile I want to implement multiple middleware in my Next.js app. Here's my `withLocale.ts` file:
import { NextResponse, NextRequest } from 'next/server';
import acceptLanguage from 'accept-language';
import { fallbackLng, languages } from '@/app/i18n/settings';
import { PATH_LOGIN } from '@/config/path';
acceptLanguage.languages(languages);
export const config = {
matcher: [
'/((?!api|_next/static|_next/image|assets|favicon.ico|sw.js|manifest.json).*)',
],
};
const cookieName = 'i18next';
export function withLocale(req: NextRequest) {
if (
req.nextUrl.pathname.indexOf('icon') > -1 ||
req.nextUrl.pathname.indexOf('chrome') > -1
)
return NextResponse.next();
let lng: string | null = '';
if (req.cookies.has(cookieName))
lng = acceptLanguage.get(req.cookies.get(cookieName)?.value);
if (!lng) lng = acceptLanguage.get(req.headers.get('Accept-Language'));
if (!lng) lng = fallbackLng;
// Exclude specific routes from redirection
const excludedRoutes = ['/welcome', PATH_LOGIN];
// Redirect if lng in path is not supported
if (
!languages.some((loc) => req.nextUrl.pathname.startsWith(`/${loc}`)) &&
!req.nextUrl.pathname.startsWith('/_next') &&
req.nextUrl.pathname !== '/' &&
!excludedRoutes.includes(req.nextUrl.pathname)
) {
return NextResponse.redirect(
new URL(`/${lng}${req.nextUrl.pathname}`, req.url),
);
}
if (req.headers.has('referer')) {
const refererUrl = new URL(req.headers.get('referer')!);
const lngInReferer = languages.find((l) =>
refererUrl.pathname.startsWith(`/${l}`),
);
const response = NextResponse.next();
if (lngInReferer) response.cookies.set(cookieName, lngInReferer);
return response;
}
return NextResponse.next();
}
export default withLocale;
Tldr. Sorry 😦
1) NextJS 13 doesn't support multiple middlewares.
2) Why are exporting the middleware and also default exporting it? Just default export it. (In the withLocale middleware)
Now onto the main point:
Next-auth's middleware can be modified so that you can add additional logic both related and unrelated, take a look at the middleware function:
https://next-auth.js.org/configuration/nextjs#wrap-middleware
1) NextJS 13 doesn't support multiple middlewares.
2) Why are exporting the middleware and also default exporting it? Just default export it. (In the withLocale middleware)
Now onto the main point:
Next-auth's middleware can be modified so that you can add additional logic both related and unrelated, take a look at the middleware function:
https://next-auth.js.org/configuration/nextjs#wrap-middleware
@Clown Tldr. Sorry 😦
1) NextJS 13 doesn't support multiple middlewares.
2) Why are exporting the middleware and also default exporting it? Just default export it. (In the withLocale middleware)
Now onto the main point:
Next-auth's middleware can be modified so that you can add additional logic both related and unrelated, take a look at the middleware function:
https://next-auth.js.org/configuration/nextjs#wrap-middleware
West African CrocodileOP
1) Yes, but i've seen articles all over implementing it. The only problem for me (as I understand) is that they describe the situation when the middleware functions are custom written, and my case is different because it's provided by Next-Auth. I think it's possible to make them work together, it's just I don't have enough JS/TS knowledge
2) It's because i've been trying multiple versions and some of them were wrappers
2) It's because i've been trying multiple versions and some of them were wrappers
https://next-auth.js.org/configuration/nextjs#wrap-middlewareI've tried doing that too, couldn't make it work. I just don't understand how to run two middleware functions with different config path matchers
Hmm... i haven't had to personally do this so im not 100% sure that there is any other way than conditional checking when you want different middlewares functionality for different paths:
https://nextjs.org/docs/pages/building-your-application/routing/middleware#conditional-statements
https://nextjs.org/docs/pages/building-your-application/routing/middleware#conditional-statements
Answer
West African CrocodileOP
i think you might be right. thank you anyway!
@West African Crocodile i think you might be right. thank you anyway!
If this is resolved, please mark the answer
Original message was deleted
Netherland Dwarf
Thanks for posting this @West African Crocodile ! I was so confused about how there doesn't seem to be any formal examples in the NextJS docs for chaining multiple middleware, and searching the web turned up nothing. Your was the first example that made sense to me, thank you 😊 Seems like there needs to be an improvement to the docs there.