0

I am using Next.js version 13.4.7 and have implemented a middleware that handles redirection based on a token. Now, I want to add a middleware for internationalization (i18n) using next-intl, but I am unsure how to chain multiple middlewares together in Next.js. Below is my code:

import { NextRequest, NextResponse } from 'next/server'
import jwt from 'jsonwebtoken'
import createMiddleware from 'next-intl/middleware'

const locales = ['en', 'fr']
const publicPages = ['/', '/signin', '/register']
const verifPages = ['/verifyaccount', '/resetpassword']

const i18nMiddleware = createMiddleware({
  locales,
  defaultLocale: 'en',
})

export const middleware = (request: NextRequest) => {
  i18nMiddleware(request)
  const path = request.nextUrl.pathname

  const publicPathnameRegex = RegExp(
    `^(/(${locales.join('|')}))?(${publicPages.join('|')})?/?$`,
    'i'
  )

  const verifPathnameRegex = RegExp(
    `^(/(${locales.join('|')}))?(${verifPages.join('|')})?/?$`,
    'i'
  )

  const isPublicPage = publicPathnameRegex.test(path)
  const isVerifPage = verifPathnameRegex.test(path)

  const token = request.cookies.get('token')?.value || ''
  const decodedToken: any = jwt.decode(token)
  const headQuarter = decodedToken?.headQuarter
  const redirectUrl = `/fr/hxoo/${headQuarter}/dashboard`

  if (isPublicPage && token && !isVerifPage) {
    return NextResponse.redirect(new URL(redirectUrl, request.nextUrl))
  }

  if (!isPublicPage && !token && !isVerifPage) {
    return NextResponse.redirect(new URL('/signin', request.nextUrl))
  }

  if (!isPublicPage && token) {
    const routeAccess = decodedToken?.routeAccess

    const pathParts = path.split('/')
    const route = `/${pathParts[3]}`

    if (!routeAccess.includes(route)) {
      return NextResponse.redirect(new URL(redirectUrl, request.nextUrl))
    }
  }

  return NextResponse.next()
}

export const config = {
  matcher: [
    '/((?!api|_next|.*\\..*).*)',
  ],
}

I would appreciate any help on how to properly chain multiple middlewares in Next.js.

1 Answers1

0

Had the same issue for a project in the past and ended up creating a folder called middlewares, in this folder each individual middleware would have their own file with a named default export like so:

import { type NextRequest, NextResponse } from "next/server";

export default function MyMiddlware(request: NextRequest) {
  if (myCondition) return NextResponse.redirect(/*...*/);
  return undefined;
}

If the condition was met I had a NextResponse object returned, if not I simply returned undefined. In the middleware file I then imported all of the required middlewares and executed them sequentially like so:

import { type NextRequest, NextResponse } from "next/server";

import MyMiddlware from "middlewares/MyMiddlware";
import MyOtherMiddleware from "middlewares/MyOtherMiddlware";

// middlewares to run in the order of the array
const middlewares = [MyMiddlware, MyOtherMiddlware];

export default async function middleware(request: NextRequest) {
  // if a response is returned, return it otherwise call `next()`
  for (const fn of middlewares) {
    const response = await fn(request);
    if (response) return response;
  }

  return NextResponse.next();
}

As you can see in the middleware file itself I simply loop through the imported middlewares and return their result if it is not undefined otherwise I call NextResponse.next().

Fabio Nettis
  • 1,150
  • 6
  • 18