Do I need to protect server components
Answered
Forest bachac posted this in #help-forum
Forest bachacOP
I have a nextjs app using nextjs-auth0 and typescript. I'm a little confused about what I need to protect using auth0. I have read somewhere that components cannot be navigated to, only pages. I have also tried navigating to both server and client components as well as sending post requests to server components and I can't seem to do it. However, I have also read that server actions are like POST requests and should be treated like APIs.
Also, I'm using nextjs-auth0 v4 which doesn't have "withAuthenticationRequired", so I have to use getSession() and check for the user.
So, questions:
1) Do I need to protect all server components that return any sesitive data?
2, a) If yes, is the best way to use getSession() on each component/method.
2, b) Or is it better to use middleware. In which case, if I use the matcher, should I then use redirects to prevent particular role groups from accessing certain functions?
Also, I'm using nextjs-auth0 v4 which doesn't have "withAuthenticationRequired", so I have to use getSession() and check for the user.
So, questions:
1) Do I need to protect all server components that return any sesitive data?
2, a) If yes, is the best way to use getSession() on each component/method.
2, b) Or is it better to use middleware. In which case, if I use the matcher, should I then use redirects to prevent particular role groups from accessing certain functions?
Answered by luis_llanes
Middleware is a good place to start doing auth checks, for completely static pages that are only generated once at built time (or ISR) middleware is the only way to keep unauthorized users from accessing them
For dynamic pages you could also add an auth checks at the top of the page and redirect the user to corresponding sign-in, not found, or whatever page you want if they’re not authorized
For dynamic pages you could also add an auth checks at the top of the page and redirect the user to corresponding sign-in, not found, or whatever page you want if they’re not authorized
21 Replies
Forest bachacOP
Am I posting in the right channel here?
Middleware is a good place to start doing auth checks, for completely static pages that are only generated once at built time (or ISR) middleware is the only way to keep unauthorized users from accessing them
For dynamic pages you could also add an auth checks at the top of the page and redirect the user to corresponding sign-in, not found, or whatever page you want if they’re not authorized
For dynamic pages you could also add an auth checks at the top of the page and redirect the user to corresponding sign-in, not found, or whatever page you want if they’re not authorized
Answer
Was this helpful?
@luis_llanes Middleware is a good place to start doing auth checks, for completely static pages that are only generated once at built time (or ISR) middleware is the only way to keep unauthorized users from accessing them
For dynamic pages you could also add an auth checks at the top of the page and redirect the user to corresponding sign-in, not found, or whatever page you want if they’re not authorized
Odorous house ant
Hey! Sorry to step in but, is there any way to do a fetch to get user subscription status and redirect out if not active? I want to ISR some pages but need to keep out unauthorized users or users without an active subscription
@Odorous house ant Hey! Sorry to step in but, is there any way to do a fetch to get user subscription status and redirect out if not active? I want to ISR some pages but need to keep out unauthorized users or users without an active subscription
Yes middleware is the only place you can do that for ISR pages, Middleware will intercept any request to the server, including the ones that request a Static Prebuilt page.
@luis_llanes Yes middleware is the only place you can do that for ISR pages, Middleware will intercept any request to the server, including the ones that request a Static Prebuilt page.
Odorous house ant
Thing is that I'm using a server action that uses PayloadCMS' API to first get the user and then its subscription, but I get this error (because middleware does not run on node I suppose):
Build Error
Next.js (15.1.6) out of date (learn more)
Failed to compile
node:fs
Module build failed: UnhandledSchemeError: Reading from "node:fs" is not handled by plugins (Unhandled scheme).
Webpack supports "data:" and "file:" URIs by default.
You may need an additional plugin to handle "node:" URIs.
Should I try with route?
@Odorous house ant Thing is that I'm using a server action that uses PayloadCMS' API to first get the user and then its subscription, but I get this error (because middleware does not run on node I suppose):
`Build Error
Next.js (15.1.6) out of date (learn more)
Failed to compile
node:fs
Module build failed: UnhandledSchemeError: Reading from "node:fs" is not handled by plugins (Unhandled scheme).
Webpack supports "data:" and "file:" URIs by default.
You may need an additional plugin to handle "node:" URIs.`
What’s the logic inside the Server Action for fetching the user session and redirecting if not authorized ?
Is it a Fetch call to a Payload URL? (I’ve never used payload)
Is it a Fetch call to a Payload URL? (I’ve never used payload)
If that’s a simple fetch call to Payload’s servers you could extract that logic into a utility function and use it in both the middleware and in the Server Action for whatever checks you used it for before.
// lib/auth.ts
async function fetchUserSubscription( … ) {
// your implementation
}
// lib/auth.ts
async function fetchUserSubscription( … ) {
// your implementation
}
Odorous house ant
Right now I was using their local api which uses drizzle to connect to Supabase, they also provide a REST API, but can't get it to work neither
Odorous house ant
Ok never mind, I just got it to work 🙂 Thank you anyways!
@Odorous house ant Ok never mind, I just got it to work 🙂 Thank you anyways!
How did you do it at the end?
@luis_llanes How did you do it at the end?
Odorous house ant
I used the REST API instead, made some tweaks and it worked
@luis_llanes Middleware is a good place to start doing auth checks, for completely static pages that are only generated once at built time (or ISR) middleware is the only way to keep unauthorized users from accessing them
For dynamic pages you could also add an auth checks at the top of the page and redirect the user to corresponding sign-in, not found, or whatever page you want if they’re not authorized
Forest bachacOP
Thank you for your reply. That is helpful. My specific question though, do I need to add paths to the matcher in middleware for the server actions as well as the pages? Or will adding the pages do? Also, how do I do role based authentication in middleware? Do I have to add conditions in middleware that check for for roles for every page?
Use middleware to check for common auth checks that are consistent across all request, like if there’s a user or not. I would leave the user role checks to the individual pages (or wrap the pages that share the same auth checks in a template.tsx and do it there)
Example:
Your /admin/… routes require the user to have the role “admin”
By the time you hit this page you know there’s a user logged in, you don’t know their role so in your /admin/ section you can add a template.tsx that does that check and redirect if they’re not allowed
<AdminLayout>
<AdminTemplate> // checks here
<DashboardPage> // or individual checks here
Example:
Your /admin/… routes require the user to have the role “admin”
By the time you hit this page you know there’s a user logged in, you don’t know their role so in your /admin/ section you can add a template.tsx that does that check and redirect if they’re not allowed
<AdminLayout>
<AdminTemplate> // checks here
<DashboardPage> // or individual checks here
And I’m not sure you can run middleware before every server action call, I don’t think so since middleware runs on the edge before a request and SA run on the server.
You should consider a Server Action as a public facing endpoint and do auth checks in there.
Server Actions submit to whatever endpoint you're currently on. So if you have checks for this page already then that ServerAction call will never be made from that page,
but if you call the same Server Action from 2 different pages and one of them is auth protected and the other is not, the protected route will not make the call, but the public page will, even though is the same Server Action.
Also if you hit that endpoint from a different client (say postman) you loose the protection that’s why you need to do local checks, and that’s what the Next.js team recommend.
You should consider a Server Action as a public facing endpoint and do auth checks in there.
Server Actions submit to whatever endpoint you're currently on. So if you have checks for this page already then that ServerAction call will never be made from that page,
but if you call the same Server Action from 2 different pages and one of them is auth protected and the other is not, the protected route will not make the call, but the public page will, even though is the same Server Action.
Also if you hit that endpoint from a different client (say postman) you loose the protection that’s why you need to do local checks, and that’s what the Next.js team recommend.
@luis_llanes Use middleware to check for common auth checks that are consistent across all request, like if there’s a user or not. I would leave the *user role* checks to the individual pages (or wrap the pages that share the same auth checks in a template.tsx and do it there)
Example:
Your /admin/… routes require the user to have the role “admin”
By the time you hit this page you know there’s a user logged in, you don’t know their role so in your /admin/ section you can add a template.tsx that does that check and redirect if they’re not allowed
<AdminLayout>
<AdminTemplate> // checks here
<DashboardPage> // or individual checks here
Forest bachacOP
Thanks again @luis_llanes
it's becoming much clearer now, but I do still have a couple of question:
I don't quite understand this paragraph:
"Server Actions submit to whatever endpoint you're currently on. So if you have checks for this page already then that ServerAction call will never be made from that page,"
Why will the server action not get called from the page the page that already has checks? Are you saying that it will not get calledif the user is not authenticated but will if they are authenticated? Or are you saying it will never get called when their are already checks, and if that is what you mean, can you explain why?
Another question that you seem to have answered, but I just want clarification... So it IS possible to call a Server Action from Postman? How do you do that? Because I tried to do that as a test and I wasn't able to. I basically did a post request to the following endpoint as an example:
http://localhost:3000/components/actions/someaction
it's becoming much clearer now, but I do still have a couple of question:
I don't quite understand this paragraph:
"Server Actions submit to whatever endpoint you're currently on. So if you have checks for this page already then that ServerAction call will never be made from that page,"
Why will the server action not get called from the page the page that already has checks? Are you saying that it will not get calledif the user is not authenticated but will if they are authenticated? Or are you saying it will never get called when their are already checks, and if that is what you mean, can you explain why?
Another question that you seem to have answered, but I just want clarification... So it IS possible to call a Server Action from Postman? How do you do that? Because I tried to do that as a test and I wasn't able to. I basically did a post request to the following endpoint as an example:
http://localhost:3000/components/actions/someaction
First question, Imagine this:
you have auth checks in “/admin/dashboard” and the user needs to be logged in and needs to have the admin role.
You have a simple form that calls addProductServerAction, by the time you click the submit button and the Server Action gets called you know for a fact that the user has been authenticated and authorized to perform that action, otherwise this page wouldn’t even be shown, user would have been redirected if they weren’t logged in and if they didn’t have the admin role
Second question about calling a Seveer Actions from another client like Postman or CURL:
yes that was possible, not (completely) sure if that’s still the case in recent versions but Next.js has always recommended to treat Server Actions as Public Endpoints, the way this worked was because Server Actions were assigned an ID and that ID was sent in the Headers when you made the request to call the Server Action.
Example (very simple demonstration, this isn’t true in the real life):
localhost:3000/admin/dashboard
Headers: NEXT-ACTION: 1H8Y33628XXXX
This will hit the endpoint and unless you have checks inside the Server Action itself you’re not protected, they’re merely a POST endpoint
you have auth checks in “/admin/dashboard” and the user needs to be logged in and needs to have the admin role.
You have a simple form that calls addProductServerAction, by the time you click the submit button and the Server Action gets called you know for a fact that the user has been authenticated and authorized to perform that action, otherwise this page wouldn’t even be shown, user would have been redirected if they weren’t logged in and if they didn’t have the admin role
Second question about calling a Seveer Actions from another client like Postman or CURL:
yes that was possible, not (completely) sure if that’s still the case in recent versions but Next.js has always recommended to treat Server Actions as Public Endpoints, the way this worked was because Server Actions were assigned an ID and that ID was sent in the Headers when you made the request to call the Server Action.
Example (very simple demonstration, this isn’t true in the real life):
localhost:3000/admin/dashboard
Headers: NEXT-ACTION: 1H8Y33628XXXX
This will hit the endpoint and unless you have checks inside the Server Action itself you’re not protected, they’re merely a POST endpoint
Like I said, I’m not sure this is still the case since I heard they made Server Actions more secure by re-assigning the ID that identifies them periodically, and they’ve made it much harder to be hit publicly.
Of course, happy to help;)