0

I'm working on a Next.js 14 App Router project where I need to integrate two middlewares: Kinde authentication middleware (for protected routes like /dashboard). next-intl middleware (for internationalization on routes like /en or /de). Since Next.js only supports a single middleware export, I can't use two separate middlewares. Here's what my code looks like:

  1. next-intl middleware:
import createMiddleware from 'next-intl/middleware';
import {routing} from '@/i18n/routing';

export default createMiddleware(routing);

export const config = {
    // Match only internationalized pathnames
    matcher: ['/', '/(en|fr|ar)/:path*']
};
  1. kinde withAuth middleware:
import {
    authMiddleware,
    withAuth,
} from "@kinde-oss/kinde-auth-nextjs/middleware";

export default function middleware(req: Request) {
    return withAuth(req);
}

export const config = {
    matcher: ["/dashboard"],
};

I considered calling both middleware functions in the same file, but I'm not sure how to structure the logic correctly to handle both authentication and internationalization.

1 Answer 1

0

create a folder named middlewares containing this the files:

  1. i18nMiddleware:

import {
    NextResponse,
    type NextFetchEvent,
    type NextRequest
} from 'next/server'
import { CustomMiddleware } from './chain'
import createMiddleware from "next-intl/middleware";
import {routing} from "@/i18n/routing";

export function withI18nMiddleware(middleware: CustomMiddleware) {
    return async (request: NextRequest, event: NextFetchEvent) => {
        // The first middleware in the chain has to create the response

        // Internationalisation with next-intl middleware
        const handleI18nRouting = createMiddleware(routing);
        console.log("middleware ai18n called")
        let response = NextResponse.next()
        try {
            response = handleI18nRouting(request)
        }catch (e){
            console.log("error in i18n middleware", e)
        }

        // Call the next middleware and pass the request and response
        return middleware(request, event, response)
    }
}

  1. authmiddleware.ts:

import {
    NextResponse,
    type NextFetchEvent,
    type NextRequest
} from 'next/server'

import { CustomMiddleware } from './chain'
import {
    authMiddleware,
    withAuth,
} from "@kinde-oss/kinde-auth-nextjs/middleware";

export function withAuthMiddleware(middleware: CustomMiddleware) {
    return async (
        request: NextRequest,
        event: NextFetchEvent,
        response: NextResponse
    ) => {

        // Check the authentication using Kinde-Auth middleware
        const protectedRoutes = ['/dashboard', '/en/dashboard', '/fr/dashboard', '/ar/dashboard'];
        const isProtectedRoute = protectedRoutes.some(route => request.nextUrl.pathname.startsWith(route));
        if (isProtectedRoute) {
            console.log("middleware auth called")
            return withAuth(request);
        }else {
            // Call the next middleware and pass the request and response
            return middleware(request, event, response)
        }


    }
}

  1. chain.ts:

import { NextMiddlewareResult } from 'next/dist/server/web/types'
import { NextResponse } from 'next/server'
import type { NextFetchEvent, NextRequest } from 'next/server'

export type CustomMiddleware = (
    request: NextRequest,
    event: NextFetchEvent,
    response: NextResponse
) => NextMiddlewareResult | Promise<NextMiddlewareResult>

type MiddlewareFactory = (middleware: CustomMiddleware) => CustomMiddleware

export function chain(
    functions: MiddlewareFactory[],
    index = 0
): CustomMiddleware {
    const current = functions[index]
    console.log("middleware called")
    if (current) {
        const next = chain(functions, index + 1)
        return current(next)
    }

    return (
        request: NextRequest,
        event: NextFetchEvent,
        response: NextResponse
    ) => {
        return response
    }
}

Then inside the middlware.ts put the code:

import { chain } from '@/middlewares/chain'
import {withI18nMiddleware} from "@/middlewares/i18nMiddleware";
import {withAuthMiddleware} from "@/middlewares/authMiddleware";


const middlewares = [ withI18nMiddleware, withAuthMiddleware]
export default chain(middlewares)

export const config = {
    // Match only internationalized pathnames
    matcher: ['/', '/(en|fr|ar)/:path*']
};

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.