Chaining multiple middleware (next-auth and multi locale) in Next.js 13

194 views Asked by At

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;

and here is my 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. 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.

0

There are 0 answers