Middleware not executing fine on production
Unanswered
American black bear posted this in #help-forum
American black bearOP
I recently migrated my project from Next.js 14's pages router to the app router. We are utilizing two different layouts, so our app directory looks something like this:
As I am using the src folder, the middleware resides inside src/middleware, which is the same directory as the app (src/app). However, the middleware is not executing as expected in production, although it functions properly locally.
|-- app
|--- (main)
|---- layout.tsx
|---- page.tsx
|--- (auth)
|---- layout.tsx
|---- page.tsx
|--- layout.tsxAs I am using the src folder, the middleware resides inside src/middleware, which is the same directory as the app (src/app). However, the middleware is not executing as expected in production, although it functions properly locally.
91 Replies
Can you explain more on what is the expected behavior and what is the actual behavior of the middleware in prod
American black bearOP
If the user is not authenticated, they should be redirected to /auth and should never go to /
if the user is authenticated, then they should not be able to see /auth page but /
basically, the middleware is not "checking" some pages, so sometimes when I am not authenticated I am able to go to / and vice versa
if the user is authenticated, then they should not be able to see /auth page but /
basically, the middleware is not "checking" some pages, so sometimes when I am not authenticated I am able to go to / and vice versa
If am authenticated I can also go to /auth
this is my current code:
import { NextRequest, NextResponse } from 'next/server'
import { cookies } from 'next/headers'
const protectedRoutes = ['/']
const publicRoutes = ['/auth']
export default async function middleware(req: NextRequest) {
const path = req.nextUrl.pathname
const isProtectedRoute = protectedRoutes.includes(path)
const isPublicRoute = publicRoutes.includes(path)
const cookie = cookies().get('token')?.value
if (isProtectedRoute && !cookie) {
return NextResponse.redirect(new URL('/auth', req.nextUrl))
}
if (isPublicRoute && !!cookie) {
return NextResponse.redirect(new URL('/', req.nextUrl))
}
return NextResponse.next()
}I removed matcher on purpose
I just copied this example from vercel/nextjs docs anda adapted to my use case
I believe the reason is that (auth) is on parenthesis so its not being take in count as a route , just as a layout group, if you want to use/auth/... try removing those parenthesis , also you have to folders with () at the same level that have a page on them , that can cause problem bc you have to pages with the same route / doesnt know if go to (auth) or (main)
i could be wrong tho , I'm still new too , but I was having a similar problem a few days ago
In relation to what cheka said above, are your file routes literally named "(main)" and "(auth)"? If so, try removing the parenthesis and check again
but should I keep auth/page.tsx?
with layout etc?
yes keeping the layout and page on auth its ok
it will take the loot layout first
and then put the auth layout inside it
American black bearOP
but how do I avoid the creation of multiple layouts?
and then the page
American black bearOP
is it bad to keep?
@American black bear but how do I avoid the creation of multiple layouts?
leave ( ) on both but just leave a page.tsx
on one of them
for login regites etc
American black bearOP
should I keep the folder called main?
You can keep the parenthesis on the main one so that the page.tsx under it becomes the path "/". The page.tsx on the auth then becomes "/auth"
|-- app
|--- (main)
|---- layout.tsx
|---- page.tsx
|--- auth
|---- layout.tsx
|---- page.tsx
|--- layout.tsxAmerican black bearOP
ok I see
this is what I have
this is what I have
You can delete the layouts under main and auth, unless you're doing something specific for those routes
my guess he wants them there bc i think he wants a layout for main and auth
American black bearOP
yeah but i can still go to auth page
@cheka my guess he wants them there bc i think he wants a layout for main and auth
American black bearOP
yes
different layouts as you guys can see in the recording
American black bearOP
right
but this is already happening
const isProtectedRoute = protectedRoutes.includes(path)
American black bearOP
I just want to prevent typing /auth in the url and go to auth
ok so just to make sure
try with a console.log
after thos booleans
too see what they are returning
American black bearOP
I mean, locally this is working perfectly
it's bad to send logs to prod
it doesn't make sense right
aah forgot that you were doing this on prod
American black bearOP
yeah
that's pretty bad and doesn't make sense tbh
I also tried building the application and running like prod with npm run start
nothing happened either
to make sure
is the cookie there?
(Isprotectedroute && !cookie) is (false && false) which makes it true?
Thus redirecting to /auth
@cheka is the cookie there?
American black bearOP
yes it's
@Berlim (Isprotectedroute && !cookie) is (false && false) which makes it true?
American black bearOP
hmmm
I see
I have something similar, maybe you can do this logic instead
export default auth((req) => {
const { nextUrl } = req;
const isLoggedIn = !!req.auth;
const isApiAuthRoute = nextUrl.pathname.startsWith(apiAuthPrefix);
const isPublicRoute = publicRoutes.includes(nextUrl.pathname);
const isAuthRoute = authRoutes.includes(nextUrl.pathname);
if (isApiAuthRoute) {
return;
}
if (isAuthRoute) {
if (isLoggedIn) {
return Response.redirect(new URL(DEFAULT_LOGIN_REDIRECT, nextUrl));
}
return;
}
if (!isLoggedIn && !isPublicRoute) {
return Response.redirect(new URL("/auth/login", nextUrl));
}
return;
})Dint include auth routes in public routes
oooh true
what auth are you using?
American black bearOP
so are you protecting them?
@cheka what auth are you using?
American black bearOP
custom auth from my api
Route.ts
// Public routes
export const publicRoutes = [
"/"
];
export const authRoutes = [
'/auth/login',
'/auth/register',
'/auth/error',
'/auth/reset',
'/auth/new-verification',
'/auth/new-password'
];
export const apiAuthPrefix = '/api/auth';
export const DEFAULT_LOGIN_REDIRECT = "/settings"
// Public routes
export const publicRoutes = [
"/"
];
export const authRoutes = [
'/auth/login',
'/auth/register',
'/auth/error',
'/auth/reset',
'/auth/new-verification',
'/auth/new-password'
];
export const apiAuthPrefix = '/api/auth';
export const DEFAULT_LOGIN_REDIRECT = "/settings"
Im checking if the route is an auth route, then check if user logged in, if so, redirect to home page
This was from code with antonio auth v5 tutorial in youtube
American black bearOP
ok and what about your folder structure?
8 hours tutorial deep dive on next-auth / auth.js
American black bearOP
do you have (auth)/login/page.tsx?
American black bearOP
oh mate, I appreciate
This repo has 2FA, password reset, email confirmation etc
American black bearOP
yeah yeah thanks, I'll take a look
the most boring thing is to deploy this to prod to test
lmao
Real
American black bearOP
sent to prod, praying xD
still not working 

😮💨 what does the new middleware look like
American black bearOP
import { NextRequest, NextResponse } from 'next/server'
import { cookies } from 'next/headers'
const authRoutes = ['/auth/login']
export default async function middleware(req: NextRequest) {
const path = req.nextUrl.pathname
const isAuthenticated = !!cookies().get('token')?.value
const isAuthRoutes = authRoutes.includes(path)
if (isAuthRoutes) {
if (isAuthenticated) {
return Response.redirect(new URL('/', req.nextUrl))
}
return
}
if (!isAuthenticated) {
return Response.redirect(new URL('/auth/login', req.nextUrl))
}
return NextResponse.next()
}
// Routes Middleware should not run on
export const config = {
matcher: ['/((?!api|_next/static|_next/image|.\.png$).)'],
}
import { cookies } from 'next/headers'
const authRoutes = ['/auth/login']
export default async function middleware(req: NextRequest) {
const path = req.nextUrl.pathname
const isAuthenticated = !!cookies().get('token')?.value
const isAuthRoutes = authRoutes.includes(path)
if (isAuthRoutes) {
if (isAuthenticated) {
return Response.redirect(new URL('/', req.nextUrl))
}
return
}
if (!isAuthenticated) {
return Response.redirect(new URL('/auth/login', req.nextUrl))
}
return NextResponse.next()
}
// Routes Middleware should not run on
export const config = {
matcher: ['/((?!api|_next/static|_next/image|.\.png$).)'],
}
I also changed (main) to (protected) just like you
and created inside auth a folder called login with a page inside
auth/login/page.tsx
@American black bear import { NextRequest, NextResponse } from 'next/server'
import { cookies } from 'next/headers'
const authRoutes = ['/auth/login']
export default async function middleware(req: NextRequest) {
const path = req.nextUrl.pathname
const isAuthenticated = !!cookies().get('token')?.value
const isAuthRoutes = authRoutes.includes(path)
if (isAuthRoutes) {
if (isAuthenticated) {
return Response.redirect(new URL('/', req.nextUrl))
}
return
}
if (!isAuthenticated) {
return Response.redirect(new URL('/auth/login', req.nextUrl))
}
return NextResponse.next()
}
// Routes Middleware should not run on
export const config = {
matcher: ['/((?!api|_next/static|_next/image|.*\\.png$).*)'],
}
American black bearOP
&752637460550385834 can someone from next help me with this here?
Asian black bear
Don't ping moderators for non-moderation issues.