Should middleware be used for role-based routing?
Answered
Northeast Congo Lion posted this in #help-forum
Northeast Congo LionOP
My last work with Next.js professionally was with version 12. In that project, I had used a higher order component which wrapped all in the pages in the _app.tsx file and had used next-redux-wrapper and next-redux-cookie-wrapper for storing user details to handle role-based routing. Now with the latest version of Next.js out where middleware bypass issue has been resolved, should I use the middleware to handle role-based routing or should I use a higher order server component to do this? Note that I am planning to use cookies-next or iron-session for storing access token, refresh token, and user object sent from a separate back-end app upon log in.
Answered by Rottweiler
yup, I'd store only the user ID and roles in the session cookie so middleware can handle authorization efficiently. Dynamic data like avatar or display name would be fetched separately using the user ID and cached in server components or React context to keep the session light and the UI up-to date
29 Replies
@Northeast Congo Lion My last work with Next.js professionally was with version 12. In that project, I had used a higher order component which wrapped all in the pages in the _app.tsx file and had used next-redux-wrapper and next-redux-cookie-wrapper for storing user details to handle role-based routing. Now with the latest version of Next.js out where middleware bypass issue has been resolved, should I use the middleware to handle role-based routing or should I use a higher order server component to do this? Note that I am planning to use cookies-next or iron-session for storing access token, refresh token, and user object sent from a separate back-end app upon log in.
Rottweiler
With the latest Next.js, I’d leverage middleware for global role-based routing because it runs at the edge, ensuring unauthorized requests are blocked before reaching the server, which improves both security and performance. For pages requiring server-side data or fine-grained authorization, I’d use server components or HOCs to integrate role checks with SSR and per-page logic. Tokens and user data would be securely stored using
iron-session or cookies-next, with centralized verification logic shared between middleware and server-side components to maintain consistency and minimize duplication.@Rottweiler With the latest Next.js, I’d leverage middleware for global role-based routing because it runs at the edge, ensuring unauthorized requests are blocked before reaching the server, which improves both security and performance. For pages requiring server-side data or fine-grained authorization, I’d use server components or HOCs to integrate role checks with SSR and per-page logic. Tokens and user data would be securely stored using `iron-session` or `cookies-next`, with centralized verification logic shared between middleware and server-side components to maintain consistency and minimize duplication.
Northeast Congo LionOP
If my user data contains roles and other fields like avatar/profile image which can be updated from the front-end whenever needed and displayed in the navbar, should I store it together with the tokens via
iron-session/cookies-next or should I keep it in a separate cookie?@Northeast Congo Lion If my user data contains roles and other fields like avatar/profile image which can be updated from the front-end whenever needed and displayed in the navbar, should I store it together with the tokens via `iron-session`/`cookies-next` or should I keep it in a separate cookie?
Giant Angora
hi @Northeast Congo Lion you must fetch user from db in middleware on every request, i recommend you save session in db instead of cookies and fetch that session along user in middleware and to use same session and user in cmponents use React.cache in server components
@Giant Angora hi <@740951820595363851> you must fetch user from db in middleware on every request, i recommend you save session in db instead of cookies and fetch that session along user in middleware and to use same session and user in cmponents use React.cache in server components
Northeast Congo LionOP
Data fetches are not recommended in middleware as it will affect app performance
@Northeast Congo Lion Data fetches are not recommended in middleware as it will affect app performance
Rottweiler
you are right that fetching data from the database in middleware on every request can hurt performance, especially for high-traffic apps. Instead, store only essential, non-sensitive user info (like
id, roles, and minimal metadata) in the session cookie using iron-session or cookies-next, and keep dynamic fields like avatar or profile data in a separate client-side fetch or React cache in server components. This way, middleware can efficiently handle authorization without heavy database hits, while the UI can update dynamic user data on-demand without blocking the request pipeline.Giant Angora
@Northeast Congo Lion @Rottweiler how do you verify cookie then and redirect to auth page or error page?
instead of creating helper functions and use them in private routes, validate user access in Middleware.
Info: server to server request is too much fast, nearly in milliseconds, so its negligible
instead of creating helper functions and use them in private routes, validate user access in Middleware.
Info: server to server request is too much fast, nearly in milliseconds, so its negligible
@Northeast Congo Lion Data fetches are not recommended in middleware as it will affect app performance
Giant Angora
who said its not recommended???
go and read docs or maybe GitHub source code of clerk, better-auth or any other nextjs auth lib. you will see they validate user by fetch user from db in Middleware
in nextjs you choose routes on which Middleware executes with config.matcher
Giant Angora
if (pathname === '/checkout') {
if (!sessionRes) return NextResponse.redirect(authPageURL);
const cart = await db.query.cartTable.findFirst({
where: (t, o) => o.eq(t.userId, sessionRes.user.id),
with: {
items: {
with: {
product: true,
inventory: true,
},
},
},
});
if (isCartStockInvalid(cart?.items)) return NextResponse.redirect(new URL('/cart', req.url));
return;
}
/** ———————————————————————————————————————— **/
if (pathname.startsWith('/dashboard')) {
if (!sessionRes) return NextResponse.redirect(authPageURL);
if (sessionRes.user.role !== 'admin') return NextResponse.redirect(new URL('/', req.url));
return;
}Giant Angora
there are 2 points
1. slow data fetching, in my shared code that is checkout validation, and i gaurded that part so its only for one page that is recommended
2. when you need role base auth in RSC and there are alot pages e.g in my case more than 20 pages under /dashboard then its recommend to check in Middleware instead of in every page
1. slow data fetching, in my shared code that is checkout validation, and i gaurded that part so its only for one page that is recommended
2. when you need role base auth in RSC and there are alot pages e.g in my case more than 20 pages under /dashboard then its recommend to check in Middleware instead of in every page
@Northeast Congo Lion Click to see attachment
Northeast Congo LionOP
other online sources say the same as well
Giant Angora
how many your pages need role validation?
My Question @Northeast Congo Lion
in my case, full website else 4 pages needs auth so why do I check for auth and redirect to auth page in every page
in my case, full website else 4 pages needs auth so why do I check for auth and redirect to auth page in every page
@Giant Angora hi <@740951820595363851> you must fetch user from db in middleware on every request, i recommend you save session in db instead of cookies and fetch that session along user in middleware and to use same session and user in cmponents use React.cache in server components
Northeast Congo LionOP
Full website also in my case. Middleware must run fast; db queries, especially on every request, adds overhead. That's why Auth libraries like Auth.js and Better-Auth use cookies to store session data.
Giant Angora
in my case, better auth use cookies but i need to verify user role thats why i fetch session with auth.api.getSession() in Middleware
@Giant Angora in my case, better auth use cookies but i need to verify user role thats why i fetch session with auth.api.getSession() in Middleware
Northeast Congo LionOP
you can store your roles inside session cookie
@Northeast Congo Lion you can store your roles inside session cookie
Giant Angora
i think you still need auth.api.getSession, is it?
Northeast Congo LionOP
Have you enabled this? @Giant Angora
@Rottweiler you are right that fetching data from the database in middleware on every request can hurt performance, especially for high-traffic apps. Instead, store only essential, non-sensitive user info (like `id`, `roles`, and minimal metadata) in the session cookie using `iron-session` or `cookies-next`, and keep dynamic fields like `avatar` or profile data in a separate client-side fetch or React cache in server components. This way, middleware can efficiently handle authorization without heavy database hits, while the UI can update dynamic user data on-demand without blocking the request pipeline.
Northeast Congo LionOP
so you are suggesting to de-structure roles and store it with user id in session cookie and keep the remaining info in React context or local storage?
@Northeast Congo Lion Have you enabled this? <@1167415269375873044>
Giant Angora
yes i use, and sometimes i use
auth.api.getSession({ query: {disableCookieCache: true }});@Northeast Congo Lion so you are suggesting to de-structure roles and store it with user id in session cookie and keep the remaining info in React context or local storage?
Rottweiler
I’d store only user ID and roles in the session cookie using
iron-session or cookies-next, so middleware can efficiently handle authorization without frequent DB calls. Dynamic user data like avatar, display name, or preferences should be fetched on-demand in server components or cached in React context, keeping the session light and secure. This separation ensures middleware stays performant while the UI can update profile info reactively.@Rottweiler I’d store only user ID and roles in the session cookie using `iron-session` or `cookies-next`, so middleware can efficiently handle authorization without frequent DB calls. Dynamic user data like avatar, display name, or preferences should be fetched on-demand in server components or cached in React context, keeping the session light and secure. This separation ensures middleware stays performant while the UI can update profile info reactively.
Northeast Congo LionOP
so after getting user id and roles in the login API, are you telling to make a separate API call for changeable data?
@Giant Angora yes i use, and sometimes i use
ts
auth.api.getSession({ query: {disableCookieCache: true }});
Northeast Congo LionOP
Caching should be used. As the docs said, calling your database every time useSession or getSession invoked isn’t ideal.
@Northeast Congo Lion so after getting user id and roles in the login API, are you telling to make a separate API call for changeable data?
Rottweiler
yup, I'd store only the user ID and roles in the session cookie so middleware can handle authorization efficiently. Dynamic data like avatar or display name would be fetched separately using the user ID and cached in server components or React context to keep the session light and the UI up-to date
Answer
@Rottweiler yup, I'd store only the user ID and roles in the session cookie so middleware can handle authorization efficiently. Dynamic data like avatar or display name would be fetched separately using the user ID and cached in server components or React context to keep the session light and the UI up-to date
Northeast Congo LionOP
What if I store the user in another cookie?
@Northeast Congo Lion What if I store the user in another cookie?
Rottweiler
You could store the full user in another cookie, but it’s not recommended because it can get large and go stale. It’s better to keep only the user ID and roles in the cookie and fetch fresh user data when needed.