Need multiple middleware, don't know how to do it...
Unanswered
Spectacled bear posted this in #help-forum
Spectacled bearOP
Hi all,
In my app, I need 2 middleware, one for authentication (keeping the session alive, using auth.js) and one for localization
I only need to add this one line, but I'm not really sure how to do it properly?
Since I can't really define
Any and all help is, as always, greatly appreciated!!!
In my app, I need 2 middleware, one for authentication (keeping the session alive, using auth.js) and one for localization
I only need to add this one line, but I'm not really sure how to do it properly?
export { auth as middleware } from "@/auth"Since I can't really define
middleware twice in the same file..?Any and all help is, as always, greatly appreciated!!!
44 Replies
Spectacled bearOP
Here's my current middleware.ts
import type { NextRequest } from 'next/server';
import { NextResponse } from 'next/server';
import { i18n } from '../i18n-config';
import { match as matchLocale } from '@formatjs/intl-localematcher';
import Negotiator from 'negotiator';
function getLocale(request: NextRequest): string | undefined {
// Negotiator expects plain object so we need to transform headers
const negotiatorHeaders: Record<string, string> = {};
request.headers.forEach((value, key) => (negotiatorHeaders[key] = value));
// Use negotiator and intl-localematcher to get best locale
let languages = new Negotiator({ headers: negotiatorHeaders }).languages();
// @ts-ignore locales are readonly
const locales: string[] = i18n.locales;
return matchLocale(languages, locales, i18n.defaultLocale);
}
export function middleware(request: NextRequest) {
const pathname = request.nextUrl.pathname;
// `/_next/` and `/api/` are ignored by the watcher, but we need to ignore files in `public` manually.
// If you have one
if (
[
'/manifest.json',
'/favicon.ico',
// Your other files in `public`
].includes(pathname)
)
return;
// Check if there is any supported locale in the pathname
const pathnameIsMissingLocale = i18n.locales.every(
(locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`
);
// Redirect if there is no locale
if (pathnameIsMissingLocale) {
const locale = getLocale(request);
// e.g. incoming request is /products
// The new URL is now /en-US/products
return NextResponse.redirect(new URL(`/${locale}/${pathname}`, request.url));
}
}
export const config = {
// Matcher ignoring `/_next/` and `/api/`
matcher: ['/((?!_next).*)'],
};Cornish Rex
We use handler function that we define in
/middlewares/stackHandler.tsimport { NextMiddleware, NextResponse } from 'next/server';
export type MiddlewareFactory = (middleware: NextMiddleware) => NextMiddleware;
export const stackMiddlewares = (
functions: MiddlewareFactory[] = [],
index = 0
): NextMiddleware => {
const current = functions[index];
if (current) {
const next = stackMiddlewares(functions, index + 1);
return current(next);
}
return () => NextResponse.next();
};In the
middleware.ts file you just call it with the following code import { authMiddleware, stackMiddlewares } from './middlewares';
const middlewares = [authMiddleware];
export default stackMiddlewares(middlewares);Add any needed middlewares to the middlewares array
Spectacled bearOP
ok so, create a directory
I imagine that
/middlewares/, add the file, and then each middleware goes in it's own file in /middlewares? import them in middleware.ts and add them to the array?I imagine that
middleware.ts doesn't go in /middlewares, stays in /src?Cornish Rex
Yes, yes and yes 🙂
Spectacled bearOP
ok, that's great!
From my understanding then, we do this in order to merge multiple middlewares and export them as one, right?
And in theory, in this way one could add as many middleware as they need?
From my understanding then, we do this in order to merge multiple middlewares and export them as one, right?
And in theory, in this way one could add as many middleware as they need?
Cornish Rex
Yes, in theory this should work.
We only use 2 seperate middlewares in our projects, but I think there's nothing saying you can't add more.
Spectacled bearOP
I mean, I also shouldn't need any more..
I can name the individual middleware files anything, right?
Just need to export and import into middleware.ts?
I can name the individual middleware files anything, right?
Just need to export and import into middleware.ts?
Cornish Rex
Yes
Spectacled bearOP
middlewares goes in
Cause I am getting
/src, not in the root of the project, right?Cause I am getting
Cannot find module './middlewares' or its corresponding type declarations. and I don't think I have done something wrong here..?Cornish Rex
Oh, make sure to add an
index.ts in the /middlewares folder and export the individual files.Spectacled bearOP
ah ah ah gocha
export default or export?
i imagine i just import the middlewarte and export them
as an array or..?
as an array or..?
Cornish Rex
export * from './authMiddleware'Spectacled bearOP
oh
Cornish Rex
and of course
export * from './stackHandler'Spectacled bearOP
oh ok ok
so
so
what do i export from each middleware?
Cornish Rex
Just a regular named export like
export const authMiddleware = () => {...}Spectacled bearOP
instead of just middleware, right?
so fo rexample
so fo rexample
export { auth as middleware } from "@/auth" becomes export { auth as authMiddleware } from "@/auth"Cornish Rex
Oh, I would suggest just putting whatever you got in
auth.ts into the authMiddleware.ts. Otherwise you could just directly import the auth.ts from the middleware.ts file.There's no explicit need to put any files in the
middlewares directory. It's just there to keep things nice and tidy.ok so, instead of having authMiddleware in its own file I can just throw that one in middleware.ts
keep localeMiddleware in its own file
or I can also just keep both in their own files and import them in middleware.ts?
tbh Im leaning towards the 2nd option since it is cleaner, each file has its 1 purpose, easier (for me) to maintain
but im getting this error in
middleware.tsCornish Rex
import { NextResponse } from 'next/server';
import type { MiddlewareFactory } from './stackHandler';
export const authenticatedRoutes = [...];
export const authMiddleware: MiddlewareFactory =
(next) => (request, fetchEvent) => {
const { pathname, search } = request.nextUrl;
// only runs when the target is an authenticated page
if (authenticatedRoutes.indexOf(pathname) === -1) {
return next(request, fetchEvent);
}
// check for authenticated pages
const accessToken = request.cookies.get('accessToken')?.value;
const refreshToken = request.cookies.get('refreshToken')?.value;
if (!accessToken && !refreshToken) {
const searchParams = new URLSearchParams(`ref=${pathname}${search}`);
return NextResponse.redirect(new URL(`/?${searchParams}`, request.url));
}
return next(request, fetchEvent);
};This is my
authMiddleware. You can use the same pattern with your middlewares.If you apply the typings to your case it should stop complaining.
Spectacled bearOP
oh alright!
I will check it out later though, I have to leave my pc for some business
Will come back and try that out, and if it works I will mark solution
I will check it out later though, I have to leave my pc for some business
Will come back and try that out, and if it works I will mark solution
Thank you very much for your time and help!!!
Cornish Rex
Anytime. Glad I could help 🙂
Spectacled bearOP
welp it's been a while, got caught up in some family shit id rather not mention but i havent had the time or energy to work on this project since 07/19/2024 12:54 PM apparently, but I'm looking into this again 🙂
Spectacled bearOP
weird thing is, it now seems to be working, even though I've changed nothing?
nope nvm
Spectacled bearOP
so now I'm getting the following error thrown:
Should I be passing props from middleware.ts to middlewares/localeMiddleware.ts
because request.nextUrl is undefined, but I didnt have that issue when I only had the locale middleware
because request.nextUrl is undefined, but I didnt have that issue when I only had the locale middleware
by console.log'ing request, I get function
for request.nextUrl i get undefined
since that code is running, i'd assume that the chaining of the middleware is working though, no?
is there some way I could test that?
for request.nextUrl i get undefined
since that code is running, i'd assume that the chaining of the middleware is working though, no?
is there some way I could test that?