-
-
Notifications
You must be signed in to change notification settings - Fork 184
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for NextAuth v5 multiple middleware #596
Comments
I currently don't have experience with v5. We have an example within this repo as well as documentation on usage with v4. Would you be interested in setting up a pull request with an update to v5? We have a few automated tests in example-next-13-next-auth that can help to verify if the updated code works as expected. As far as I know, v5 is in beta currently though. We should wait until v5 becomes stable before updating our example in the |
Sure thing! I just made a PR, but my PR skills are a bit rusty so bear with me 🙂 |
I am trying to make it work but apparently, this does not work anymore
So I decided to follow the next-auth and next.js guidelines about this and I came up with this:
But the thing is this does not work either... |
As a temporary workaround, you can set a custom header in the middleware, and handle redirection in the main layout. In middleware.tsx export async function middleware(request: NextRequest) {
const intlMiddleware: (request: NextRequest) => NextResponse<unknown> = createMiddleware({
locales: ['en', 'dk'],
defaultLocale: 'en'
});
const session = await nextAuth(NextAuthConfiguration).auth();
if (!session) {
request.headers.set('x-auth-unauthorized', 'true');
}
return intlMiddleware(request);
} In layout.tsx const headersList = headers();
const unauthorized = headersList.get('x-auth-unauthorized') === 'true'; |
Thanks, I'm using Supabase and I was having problems as Supabase uses a middleware too. Here's my middleware.ts import createMiddleware from 'next-intl/middleware';
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs';
import { NextResponse, NextRequest } from 'next/server';
export async function middleware(req: NextRequest) {
const intlMiddleware: (request: NextRequest) => NextResponse<unknown> =
createMiddleware({
locales: ['en', 'es'],
defaultLocale: 'en',
});
const res = NextResponse.next();
const supabase = createMiddlewareClient({ req, res });
const {
data: { user },
} = await supabase.auth.getUser();
if (!user && req.nextUrl.pathname.includes('account')) {
return NextResponse.redirect(new URL('auth', req.url));
}
return intlMiddleware(req);
}
export const config = {
matcher: ['/', '/(en|es)/:path*'],
}; |
Any update on this? I'm at the same point, getting this error: And in the server:
The concrete line is this, if it helps UPDATE: It seems to be a problem with the |
What worked for me was to use the const intlMiddleware = createIntlMiddleware({
locales,
defaultLocale,
localePrefix: 'never', // we do not need the path since we are not worried about SEO
localeDetection: true,
})
export default async function middleware(req: NextRequest) {
// Init intl middleware response
const intlResponse = intlMiddleware(req)
// APIs handle their own auth, but they still need locale data
if (req.nextUrl.pathname.includes('api')) {
return intlResponse
}
// handle public routes...
// private routes here
const session = await auth()
if(session !== null) {
return intlResponse
}
// redirect to sign in if unauthorized
const nextUrl = req.nextUrl.clone()
nextUrl.pathname = '/auth/signin'
// When using redirect Next.js expects a 3xx status code otherwise it errors out
return NextResponse.redirect(nextUrl, { ...intlResponse, status: HttpCodes.PERMANENT_REDIRECT })
}
export const config = { matcher: ['/((?!_next|.*\\..*).*)'] } Note that we are not using the locale prefix in the pathname as we do not need it, so if you do this logic might change a bit but the general idea should still work. |
There is a way how to solve the issue, maybe it's not the most elegant solution, but it works as expected: interface AppRouteHandlerFnContext {
params?: Record<string, string | string[]>;
}
const i18nMiddleware = createI18nMiddleware({
locales: ['en', 'fr'],
defaultLocale: 'en',
urlMappingStrategy: 'rewriteDefault',
});
export const middleware = (request: NextRequest, event: AppRouteHandlerFnContext): NextResponse => {
return NextAuth(authConfig).auth(() => {
return i18nMiddleware(request);
})(request, event) as NextResponse;
};
export const config = {
matcher: [ '/', '/(en|fr)/:path*', '/((?!api|_next/static|_next/image|.png).*)'],
}; Passing the callback into auth middleware we receive not the original request object and it's a big problem because it doesn't have headers and cookies fields. |
This worked for me "next": "^14.1.0",
"react": "18.2.0",
"next-auth": "5.0.0-beta.13",
"next-intl": "^3.4.2", import { NextResponse } from "next/server"
import type { NextRequest } from "next/server"
import createIntlMiddleware from "next-intl/middleware"
import { auth } from "@/auth"
import { defaultLocale, localePrefix, locales } from "./messages/config"
const publicPages = [
"/",
"/unauthorized",
"/pricing",
"/roadmap",
"/features",
"/contact",
"/about",
"/help",
"/privacy-policy",
"/terms-of-service",
"/cookie-policy",
"/end-user-license-agreement"
]
const authPages = ["/sign-in", "/sign-up"]
const testPathnameRegex = (pages: string[], pathName: string): boolean => {
return RegExp(
`^(/(${locales.join("|")}))?(${pages.flatMap((p) => (p === "/" ? ["", "/"] : p)).join("|")})/?$`,
"i"
).test(pathName)
}
const intlMiddleware = createIntlMiddleware({
locales,
defaultLocale,
localePrefix
})
const authMiddleware = auth((req) => {
const isAuthPage = testPathnameRegex(authPages, req.nextUrl.pathname)
const session = req.auth
// Redirect to sign-in page if not authenticated
if (!session && !isAuthPage) {
return NextResponse.redirect(new URL("/sign-in", req.nextUrl))
}
// Redirect to home page if authenticated and trying to access auth pages
if (session && isAuthPage) {
return NextResponse.redirect(new URL("/", req.nextUrl))
}
return intlMiddleware(req)
})
const middleware = (req: NextRequest) => {
const isPublicPage = testPathnameRegex(publicPages, req.nextUrl.pathname)
const isAuthPage = testPathnameRegex(authPages, req.nextUrl.pathname)
if (isAuthPage) {
return (authMiddleware as any)(req)
}
if (isPublicPage) {
return intlMiddleware(req)
} else {
return (authMiddleware as any)(req)
}
}
export const config = {
matcher: ["/((?!api|_next|.*\\..*).*)"]
}
export default middleware |
I found this article wich is about to chain multiple middleware. I didn't try it yet, but what do you think about it, i think this would be the greate solution, to chain up multiple middlewares so you can extend your application as you need. https://reacthustle.com/blog/how-to-chain-multiple-middleware-functions-in-nextjs |
Is your feature request related to a problem? Please describe.
I use both next-intl and next-auth middleware. There are some nice examples of this combination for next-auth v4 (
withAuth()
), but not for v5 when usingauth
.Would love to see.
Describe the solution you'd like
I imagine the usage something like this:
Describe alternatives you've considered
Alternatively I can stick with using next-auth v4
The text was updated successfully, but these errors were encountered: