I have next-auth set up (in my next.js 13 project with app router), it is working. Now I want to add internationalization to my app as described in the next.js docs. However, I don't know how to combine the two.
Every route in /user/ should be protected.
export { default } from "next-auth/middleware"
export const config = { matcher: ["/(user/.*)"] }
This is what I've come up so far. I18n seems to be working, but the routes /user/... are not protected.
import { match } from '@formatjs/intl-localematcher'
import Negotiator from 'negotiator'
import { NextResponse } from 'next/server'
export { default } from "next-auth/middleware"
let locales = ['en', 'de']
let defaultLocale = 'en'
function getLocale(request) {
let headers = { 'accept-language': 'en' }
let languages = new Negotiator({ headers }).languages()
return match(languages, locales, defaultLocale) // -> 'en'
}
export function middleware(request) {
// Check if there is any supported locale in the pathname
const pathname = request.nextUrl.pathname
const pathnameIsMissingLocale = 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/products
return NextResponse.redirect(
new URL(`/${locale}/${pathname}`, request.url)
)
}
}
export const config = {
// '/(\w{2}/user/.*)' from nextauth (\w{2} because of /en/ or /de/); '/((?!_next).*)' from i18n
matcher: ['/(\w{2}/user/.*)', '/((?!_next).*)'],
}
How do I combine the two?
I just figured it out thanks to the help of @mateen-kiani and phind.com! This is how I combined the two middlewares:
import { NextResponse } from 'next/server'
import { match } from '@formatjs/intl-localematcher'
import Negotiator from 'negotiator'
import nextAuthMiddleware from "next-auth/middleware"
let locales = ['en', 'de']
let defaultLocale = 'en'
function getLocale(request) {
let headers = { 'accept-language': 'en' }
let languages = new Negotiator({ headers }).languages()
return match(languages, locales, defaultLocale) // -> 'en'
}
export function middleware(request) {
// cancel if exception
const pathname = request.nextUrl.pathname
const isException = ['/img', '/preview', '/icons', '/logo.svg', '/api', '/manifest.json', '/sw.js'].some((allowedPath) =>
pathname.startsWith(`${allowedPath}`),
);
if (isException) return;
// Check if there is any supported locale in the pathname
const pathnameIsMissingLocale = locales.every(
(locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`
)
// Redirect if there is no locale
if (pathnameIsMissingLocale) {
const locale = getLocale(request)
return NextResponse.redirect(
new URL(`/${locale}/${pathname}`, request.url)
)
}
// check if auth is required
if (pathname.includes("/user")) {
// check & handle if logged in
const nextAuthResponse = nextAuthMiddleware(request)
if (nextAuthResponse) {
return nextAuthResponse
}
}
// Continue if no NextAuth middleware response
return NextResponse.next()
}
export const config = {
matcher: [
'/((?!_next).*)',
],
}