4

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 Answer 1

4

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().

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.