Always Use DAL Authentication In Next.js (Data Access Layer)
Resumo
TLDRLe contenu de la vidéo discute des défis de l'authentification dans Next.js, en particulier après une vulnérabilité récente liée à la middleware. L'intervenant recommande d'implémenter une couche d'accès aux données pour améliorer la sécurité en intégrant des vérifications d'authentification directement dans cette couche, évitant ainsi les erreurs lors de la réutilisation de composants et réduisant le risque d'accès non autorisé aux données sensibles. Il fournit des exemples pratiques et des conseils pour structurer les applications Next.js de manière sécurisée et efficace, y compris des recommandations sur l'utilisation d'ESLint pour renforcer la sécurité du code.
Conclusões
- 🔐 Protéger les données sensibles est crucial dans une application.
- 🛡️ Une couche d'accès aux données renforce la sécurité de l'application.
- 🤖 L'IA peut générer du code, mais comportent des risques d'erreurs de sécurité.
- 📋 Utilisation de règles ESLint pour éviter l'accès non sécurisé aux données.
- ⬆️ Les composants réutilisables doivent toujours être soumis à des vérifications d'authentification.
- 🔗 Utiliser des solutions comme Kin pour des systèmes d'authentification robustes.
Linha do tempo
- 00:00:00 - 00:05:00
Dans cette vidéo, nous abordons les défis de l'authentification dans Next.js, notamment une récente vulnérabilité liée à un contournement de middleware. La solution recommandée consiste à utiliser une couche d'accès aux données, qui renforce la sécurité des applications et prévient les erreurs d'authentification.
- 00:05:00 - 00:10:00
Un exemple concret d'une application de stockage de documents secrets montre qu'une authentification uniquement via middleware est insuffisante, car cela expose les données sensibles. Pour protéger ces données, il est crucial d'intégrer des vérifications d'authentification à chaque point d'accès aux données.
- 00:10:00 - 00:15:00
Nous explorons comment Next.js permet d'effectuer des vérifications d'authentification dans des composants de page ou via middleware, mais ces méthodes peuvent laisser une lacune dans la sécurité si les composants sont réutilisés ailleurs sans vérification appropriée.
- 00:15:00 - 00:20:00
La couche d'accès aux données (DAL) est introduite comme un moyen d'unifier l'accès aux données et d'intégrer des contrôles d'authentification. Cela garantit que même si un composant est partagé sur d'autres pages, l'accès aux données est sécurisé grâce à des vérifications centralisées.
- 00:20:00 - 00:26:59
Enfin, nous discutons des meilleures pratiques pour implémenter une DAL, y compris l'établissement de règles ESLint pour empêcher l'accès direct à la base de données en dehors de cette couche, et comment gérer le rendu statique en conjonction avec des vérifications d'authentification.
Mapa mental
Vídeo de perguntas e respostas
Qu'est-ce que la couche d'accès aux données ?
C'est un emplacement centralisé où toutes les interactions avec la base de données se font, intégrant des vérifications d'authentification.
Pourquoi est-il risqué de se fier uniquement à la middleware pour l'authentification ?
La middleware peut être contournée, ce qui expose des données sensibles si des composants sont réutilisés sans vérification d'authentification.
Quelle est la différence entre les composants de page et la middleware pour l'authentification ?
Les deux peuvent être utilisés pour sécuriser les routes, mais une couche d'accès aux données est recommandée comme défense supplémentaire.
Comment protéger des routes sensibles dans Next.js ?
En utilisant une couche d'accès aux données qui intègre des vérifications d'authentification avant d'accéder aux données.
Qu'est-ce qui se passe si vous oubliez de vérifier l'authentification dans un composant ?
Si vous utilisez une fonction de la couche d'accès aux données, l'accès aux données sera toujours protégé par la vérification intégrée.
Les fonctionnalités d'authentification peuvent-elles être personnalisées ?
Oui, des solutions comme Kin offrent des options avancées pour personnaliser les flux d'authentification.
Ver mais resumos de vídeos
- 00:00:00Everyone, let's talk a little bit more
- 00:00:01about authentication in Nex.js.
- 00:00:03Unfortunately, recently there has been
- 00:00:05an issue with middleware in Nex.js where
- 00:00:09it may have been possible that some
- 00:00:11attacker could have been able to bypass
- 00:00:14middleware. So, if you were only doing
- 00:00:16the authentication check in middleware,
- 00:00:18that could potentially have been a
- 00:00:19problem. So, I've seen some people
- 00:00:21wonder about how to do authentication.
- 00:00:23Should you still do it in middleware or
- 00:00:25only in the page component or how to how
- 00:00:27to structure everything? So, I want to
- 00:00:30talk about it in this video, but I can
- 00:00:31already tell you that you probably want
- 00:00:33to look into a so-called data access
- 00:00:36layer. I've mentioned it before, and
- 00:00:38this is also something that is
- 00:00:39recommended here by the Nex.js team
- 00:00:42themselves. And by using a data access
- 00:00:44layer, you can build much more robust
- 00:00:46Nex.js applications. So, I want to dive
- 00:00:49a little bit deeper into a data access
- 00:00:51layer and look at some tips and tricks.
- 00:00:53So, let's quickly recap with why we even
- 00:00:56want this. What is wrong with just doing
- 00:00:57authentication in middleware or the p or
- 00:01:00page component? Because that's probably
- 00:01:02what you've been using so far. Either
- 00:01:04middleware or you do it directly in the
- 00:01:05page component. But there are some
- 00:01:07pitfalls. So let's take a look at an
- 00:01:09example. We have a super simple app for
- 00:01:12storing secret documents. The secret
- 00:01:14documents fault. And you can view the
- 00:01:17documents on the route/ documents. Here
- 00:01:20we have three documents but they are top
- 00:01:22secret. So we need to protect this data.
- 00:01:25So if we zoom out a little bit and take
- 00:01:27a look at how a nextjs app is typically
- 00:01:29structured. Basically this entire thing
- 00:01:32here is one next.js app. We have a
- 00:01:34client side as well as a server side.
- 00:01:36And we also have something called
- 00:01:38middleware. Right? So if we send a
- 00:01:39request from the client side to the
- 00:01:41server side, we can let it go through
- 00:01:42middleware first and then we can do
- 00:01:45other stuff. Right? So the recent
- 00:01:46security vulnerability basically had to
- 00:01:49do with bypassing middleware that should
- 00:01:51have been resolved. Now what we want to
- 00:01:53protect is the data, right? So the data
- 00:01:56is the most important thing. So if a
- 00:01:58user is able to change something in the
- 00:02:00UI or rerender the wrong button, let's
- 00:02:03say, all of that is not really a huge
- 00:02:06issue as long as the user is not able to
- 00:02:08get access to data that they should not
- 00:02:11have access to. Right? So the data is
- 00:02:13really I would say the core part that we
- 00:02:15really need to protect. Everything else
- 00:02:17around it is essentially just UI. In
- 00:02:19this case, we have secret documents. So
- 00:02:21this content here could be you know very
- 00:02:24could be top secret right could be could
- 00:02:26be the launch codes we need to be really
- 00:02:28careful with who gets access to this and
- 00:02:30right now it's a public route everybody
- 00:02:33can go here right so if I go to the
- 00:02:35homepage this is a public route and in
- 00:02:37nextg we have uh well the pagets access
- 00:02:40right here right just the homepage okay
- 00:02:42and then we have that documents route
- 00:02:44which should absolutely not be publicly
- 00:02:46accessible but right now it is we have
- 00:02:48that right here what am I doing in this
- 00:02:50page Well, I'm just grabbing all the
- 00:02:52documents from my database. I'm just
- 00:02:54using Prisma here, but works the same
- 00:02:55with any other OM or whatever you're
- 00:02:57using to access your database. And here
- 00:02:59I get all the secret documents and I'm
- 00:03:01just mapping over them here. So for each
- 00:03:03one, I'm just uh creating some markup
- 00:03:05here. And here you can see I'm
- 00:03:07outputting doc.content. That's some
- 00:03:09really sensitive data that we should not
- 00:03:12be just loosely throwing around. So how
- 00:03:16would we protect this route? Let's say
- 00:03:18we have a very simple authentication
- 00:03:19strategy. We only want to allow logged
- 00:03:23in users to access this data. Right? So
- 00:03:26when I say logged in, it basically just
- 00:03:28means that they have some valid access
- 00:03:31token. Right? Typically we have
- 00:03:32so-called session. So if as long as the
- 00:03:34user can keep showing a valid access
- 00:03:36token which can be a JSON web token JWT
- 00:03:39typically stored in a cookie and so then
- 00:03:43on every request to the server side that
- 00:03:45cookie will be sent with it and so let's
- 00:03:48try to protect this route so that only
- 00:03:50logged in users can access it. So for
- 00:03:52authentication typically you have
- 00:03:54probably used the page components in
- 00:03:57nextJS which are just server components
- 00:03:59or you've been doing it in middleware.
- 00:04:01These are the two common approaches.
- 00:04:03Now, what I want to show you in this
- 00:04:05video is actually that doing it in
- 00:04:07either of these two is actually not
- 00:04:08going to be sufficient in most cases.
- 00:04:11You you should view this more as your
- 00:04:12first line of defense, but you want to
- 00:04:14have a so-called data access layer in
- 00:04:16addition to that to make it more robust.
- 00:04:19So, let's try to protect this like how
- 00:04:21you would traditionally perhaps uh start
- 00:04:23off. Well, you would do it either
- 00:04:25directly here in the page or you would
- 00:04:27create a middleware file and do it in
- 00:04:29middleware. But let's say we do it in
- 00:04:31the page component here. So I need some
- 00:04:32kind of authentication solution and I
- 00:04:34will use KINT in this video. I'm a brand
- 00:04:36ambassador for Kind. It's a paid
- 00:04:38sponsorship but had a great time working
- 00:04:40with them. But the things we talk about
- 00:04:41here are relevant for the other
- 00:04:42solutions you may be using as well. So
- 00:04:44no matter what authentication solution
- 00:04:46you use, what we talk about here is
- 00:04:48relevant for all of them. So in this
- 00:04:49case, I like using Kite. Super fast to
- 00:04:51set up. I have other videos with them.
- 00:04:53If you want me to walk you through how
- 00:04:54to set it up, I have other videos with
- 00:04:56Kite. Make sure to check them out. But
- 00:04:57basically any authentication solution
- 00:04:59will allow you to check the incoming
- 00:05:01request to see if the user is logged in
- 00:05:04or not. So if the user is not logged in
- 00:05:05typically we do want to redirect them to
- 00:05:08the login page. This is the route I can
- 00:05:10redirect to. By the way, Nexj has a
- 00:05:12redirect and works by throwing an error.
- 00:05:15So if the code reaches this line, it
- 00:05:17will throw an error. It will not
- 00:05:19continue down here. Right? So if you
- 00:05:21really want to be explicit about it uh
- 00:05:23because it's unreachable code. Okay.
- 00:05:25Okay. So this is how a lot of people do
- 00:05:27it and it's not inherently bad. So now
- 00:05:29we have homepage as public. Now if I try
- 00:05:31to go to /documents, it should be
- 00:05:33protected, right? So let's see what we
- 00:05:35get and waiting. Yeah. So now indeed I
- 00:05:37cannot access it. I'm not logged in. I'm
- 00:05:39redirected here to a login page. So this
- 00:05:42is now properly protecting the data. So
- 00:05:45this is the default login page I get
- 00:05:47with kind. I can decide how users can
- 00:05:49login. So in this case I enabled uh
- 00:05:51GitHub login. But here are all the other
- 00:05:53options I have as well. So I can add
- 00:05:55phone, username and code, username,
- 00:05:57email and password and other social
- 00:05:59connections as well. All from the
- 00:06:01dashboard here in kind. Really nice.
- 00:06:02They now also allow you to design a
- 00:06:04custom login page. They even help you
- 00:06:06out with some nice templates here as
- 00:06:07well. So you can pretty much customize
- 00:06:09this almost in any way you want. All
- 00:06:11right, but let me actually log in here
- 00:06:12and see if our app is still working. All
- 00:06:14right, so I just logged in and I'm being
- 00:06:16redirected here to the homepage. Now if
- 00:06:18I go to slash uh documents, let's see
- 00:06:21what we get. All right. So now I can see
- 00:06:24the data again. It is protected now and
- 00:06:26I can still access it because now I am
- 00:06:29logged in. Meaning I have these tokens,
- 00:06:32right? Particularly the access token
- 00:06:34which is just a JSON web token. As long
- 00:06:37as I can show this and it's still valid,
- 00:06:39I can access the data right now. Now
- 00:06:40what is the risk with this? Because this
- 00:06:43is how a lot of people do it actually.
- 00:06:44Well, the biggest risk is that over time
- 00:06:47you will switch up your code. The way
- 00:06:50that we do it right here is we fetch the
- 00:06:51data also directly here on the page and
- 00:06:55then uh we map over it here on the page.
- 00:06:57But typically you structure your react
- 00:07:00applications a bit differently. For
- 00:07:01example, you often create dedicated
- 00:07:04component. So for this list for example,
- 00:07:06we could create a dedicated component
- 00:07:08called documents list in the components
- 00:07:11folder or wherever. I can create a
- 00:07:13component. Let's just call it documents
- 00:07:14list. Let me remove that. Right? That's
- 00:07:16typically how you structure React
- 00:07:18applications. You want to have nice,
- 00:07:20clean, reusable components. That's one
- 00:07:24of the reasons why React became so
- 00:07:25popular. It's because uh you were able
- 00:07:27to reason about your application as a
- 00:07:29tree of components. Now I have the
- 00:07:31markup here now, but it needs the data
- 00:07:33here, right? So I could pass it as a
- 00:07:35prop, right? So we will have our
- 00:07:37component here. Now we could pass it as
- 00:07:39a prop, but we can also fetch data
- 00:07:42directly in this in a React server
- 00:07:44component. Right? Right. So in nextJS we
- 00:07:46can mark it as async a server component
- 00:07:48and then just get data directly reach
- 00:07:50out to our database directly like like
- 00:07:53this not only on the page component we
- 00:07:55can do that in any react server
- 00:07:57component. So I could also do that in
- 00:07:59here and actually there are some good
- 00:08:00arguments to be made to do it in here.
- 00:08:03So I can just mark this as async as
- 00:08:05well. I can fetch the data in my react
- 00:08:08server component like this. Right? So
- 00:08:09now I don't even have to pass a prop.
- 00:08:11And now my app is structured like this.
- 00:08:13And there are some good arguments to be
- 00:08:14made to do it this way actually because
- 00:08:17you can now also wrap it in suspense. So
- 00:08:19then you can show a fallback as this is
- 00:08:21fetching the data and we're waiting for
- 00:08:23it for it to finish. Right? And there
- 00:08:25are some other reasons but we can get
- 00:08:26rid of Prisma here because we are not
- 00:08:28using Prisma in this file anymore. All
- 00:08:30right. Now what you could say what is
- 00:08:31the problem? We still have
- 00:08:33authentication here in this page right
- 00:08:35this component. Yeah. Okay. Now it's
- 00:08:36sitting in a different file but
- 00:08:38everything here is still protected.
- 00:08:39Right? If we go to this page it will
- 00:08:42still run. If we go to this page, if
- 00:08:44somebody goes here, it will still run
- 00:08:45this code first before we get to here.
- 00:08:48So, this is all uh this is all safe,
- 00:08:50right? Well, now what could happen is
- 00:08:53you or somebody else on your team or
- 00:08:55importantly AI, right? An insane amount
- 00:08:58of code these days is being generated
- 00:09:00with AI and AI is really good and it is
- 00:09:03still getting better of course, but
- 00:09:05sometimes if it's if it's if something
- 00:09:07is really tricky, it may not do it
- 00:09:09properly. So what could happen is that
- 00:09:11somebody could reuse this component
- 00:09:14because that's what we do with React
- 00:09:16components very often. We reuse them. So
- 00:09:19somebody could use that on some other
- 00:09:20page. Let's say the homepage or any uh
- 00:09:23public page. Maybe somebody's like, "Oh,
- 00:09:25we need a documents list here." I can
- 00:09:27just reuse that component. But now this
- 00:09:30page does not have an authentication
- 00:09:31check. If I log out here, let me
- 00:09:33actually also add a log out button. So
- 00:09:36kind just gives me this log out link. So
- 00:09:38then if I click there, it will clear out
- 00:09:40my cookies and just log log me out. And
- 00:09:43you can see I'm redirected now to the
- 00:09:45homepage. But what do I see on this
- 00:09:47public homepage? I see the launch codes.
- 00:09:50I see all these secret documents. This
- 00:09:52is now publicly available. And I would
- 00:09:54say this is a reasonable risk. I
- 00:09:57wouldn't say it's extremely likely that
- 00:09:58it's going to happen, but it's still
- 00:10:00likely enough that you need to have some
- 00:10:03kind of safeguard against this. So what
- 00:10:05is the reason this could happen? Well,
- 00:10:07it's because the place where we are
- 00:10:09doing the authentication check, where we
- 00:10:11are accessing data, those two things are
- 00:10:13in different places, right? They are in
- 00:10:15different files. They're in different
- 00:10:16places. So, there is a gap between the
- 00:10:18authentication check and where we access
- 00:10:21our data. And because of that gap, there
- 00:10:23is some risk that something sort of gets
- 00:10:26in that gap. Well, in this case, what
- 00:10:27happened is where we access the data, we
- 00:10:30reuse that on some other place in some
- 00:10:32other place where there was no
- 00:10:33authentication check before there. Now,
- 00:10:35of course, you can you can prevent this
- 00:10:37by making sure that you always do the
- 00:10:40authentication check before you access
- 00:10:43data. I could technically try to add it
- 00:10:45here, but it makes more sense to have a
- 00:10:47dedicated uh place in your app. So, that
- 00:10:49was an example with the page component,
- 00:10:50but maybe you were wondering about
- 00:10:52middleware. So, we could technically
- 00:10:53also do authentication in middleware.
- 00:10:55So, with kind, I can uh wrap the request
- 00:10:57with with O. Now, client will give you
- 00:11:00the path that they recommend to use. But
- 00:11:02just as an example here, let's say I
- 00:11:04only want to protect the slashdocuments
- 00:11:07route, right? You would do something
- 00:11:08like this, right? So it it would match
- 00:11:10for the slash document because on the
- 00:11:11slash documents route, we had that
- 00:11:14secret data, right? But now what
- 00:11:16happened was with re with react, we
- 00:11:18actually put the data in a react
- 00:11:20component and then we reused that on the
- 00:11:22homepage and the homepage you can see
- 00:11:25here in middleware is also not
- 00:11:26protected. So we would have the same
- 00:11:28issue whether you use middleware or you
- 00:11:30do authentication directly in the page
- 00:11:32component it would be the same result
- 00:11:33because you could technically reuse that
- 00:11:35component on the homepage or any public
- 00:11:37page and you can see we are not we are
- 00:11:40not protecting right we don't we don't
- 00:11:41have this as in our metro here we only
- 00:11:44have / documents so we would have had
- 00:11:45the same issue if we were using
- 00:11:47middleware doing authentication in
- 00:11:49middleware or in the page component
- 00:11:51should probably only be your first line
- 00:11:53of defense so ideally we can have a more
- 00:11:55robust solution for is. So this is where
- 00:11:58a data access layer comes into play. But
- 00:12:01there are various ways that you can
- 00:12:02implement a data access layer. I'm just
- 00:12:04going to give you one example here. It's
- 00:12:06basically a dedicated place where we do
- 00:12:08all of our data access. So whenever we
- 00:12:10reach out to our database, all of that
- 00:12:12is going to go in here in one
- 00:12:14centralized place. I can literally call
- 00:12:16it data access or abbreviated Dell. Now
- 00:12:19in this case, I only have one uh table
- 00:12:22right in my database secret document. So
- 00:12:24I could create uh a a file uh per table
- 00:12:29let's say and then here all of the
- 00:12:31operations that I want to do on that
- 00:12:33table will be done with functions in
- 00:12:36here. So for example I can have a
- 00:12:38function to get all secret documents
- 00:12:41right we can just call that get secret
- 00:12:43documents or maybe even more explicit
- 00:12:46get all secret documents and it will go
- 00:12:48into my database and just return that.
- 00:12:50And importantly remember why we had that
- 00:12:52issue. This was it was because there was
- 00:12:54a gap between where we do the O check
- 00:12:56and where we access our data. So what I
- 00:12:58could do here is I can include the
- 00:13:01authentication check right in here. So
- 00:13:03now there is no gap right before I
- 00:13:05access my data. I'm first going to check
- 00:13:08my authentication status. So that's for
- 00:13:10getting all the secret documents. But
- 00:13:11you can imagine uh we can have other
- 00:13:13things like creating a secret document
- 00:13:16or deleting one or editing one or all
- 00:13:18your CRUD operations whatever you want
- 00:13:20to do. But in my example here, I'm doing
- 00:13:23an authentication check right before I
- 00:13:25access the data. So now, as long as I
- 00:13:28only use functions from this file, deal
- 00:13:31with my data, I should be safe, right?
- 00:13:34So let me see. So I removed the
- 00:13:35middleware. So let's go back to our page
- 00:13:38authentication. So let me actually
- 00:13:39remove it from the homepage and let's
- 00:13:41see what we had before. So on the slash
- 00:13:43document, we have this uh documents
- 00:13:45list. Here is where we were currently
- 00:13:47getting the data. But but now we only
- 00:13:49want to use functions from this file,
- 00:13:52right? So only functions from my data
- 00:13:55access layer. So in this case, if we
- 00:13:57want to get all the secret documents, I
- 00:13:59have to use this function. So I don't
- 00:14:01want to see Prisma elsewhere in my app
- 00:14:03anymore, right? I only want to see
- 00:14:05Prisma in this file. We can even try to
- 00:14:07set up an ESLint rule. I'll show that in
- 00:14:08a second. If I want to get uh docu, if I
- 00:14:11want to get data, I would use that
- 00:14:12function, right? So I can remove the
- 00:14:14Prisma import here as well. As long as I
- 00:14:15use that. Now if I use this uh component
- 00:14:18anywhere let's say on uh let's say on /
- 00:14:21document right of course we already had
- 00:14:23an authentication check we were saved
- 00:14:25but let's say you actually forgot it
- 00:14:27that's also possible you can simply
- 00:14:28forget to add authentication to your
- 00:14:30page um because honestly doing
- 00:14:32authentication in the page is actually
- 00:14:34quite uh messy. It's not you don't have
- 00:14:37a clear overview of which pages are
- 00:14:39protected. It's quite messy. So it's
- 00:14:41possible that you simply forget it. So
- 00:14:42let's say you have a page and you forget
- 00:14:44to do authentication but you do include
- 00:14:45your documents list component here.
- 00:14:47Well, if I now go to /documents, you
- 00:14:50will see that it is still protected. So
- 00:14:52let's actually see. You can see I'm
- 00:14:54still redirected now to the login page
- 00:14:55because how are we getting data in
- 00:14:57there? Well, it's using this Dell
- 00:15:00function and in every Dell function I
- 00:15:02have an authentication check. So before
- 00:15:04I actually access data, it has a uh
- 00:15:07authentication check. Even if I forgot
- 00:15:09it here, I would still be protected.
- 00:15:10That's why I said that authentication in
- 00:15:12your page component or in middleware
- 00:15:15that's more like a first line of
- 00:15:16defense. Now how about that other issue?
- 00:15:18If you actually reuse it on a public
- 00:15:20route, right? So we have a homepage. If
- 00:15:22I go here, I have a homepage here.
- 00:15:24Remember this is a public route. So if I
- 00:15:26go to the homepage, it's a public route.
- 00:15:27Now what if somebody maybe you or an AI
- 00:15:30reuses that component here documents
- 00:15:32list. Now previously we leaked all the
- 00:15:34data. But now if I add it to the
- 00:15:36homepage here, you can see actually I'm
- 00:15:38already being redirected. If I try to go
- 00:15:40to the homepage now, it is actually uh
- 00:15:42going to redirect me because this
- 00:15:44documents list component to get the data
- 00:15:47is using my Dell function and my Dell
- 00:15:49function has the authentication check
- 00:15:51right here. I was not logged in so I'm
- 00:15:53being redirected, right? And if you were
- 00:15:55using middleware, right, and you
- 00:15:56accidentally added a documents list on
- 00:15:59the homepage, which we would not protect
- 00:16:01with middleware right now, that would
- 00:16:03not be the end of the world because to
- 00:16:05get data, it's using a function from my
- 00:16:07data access layer and that has already
- 00:16:09built in the authentication check. So
- 00:16:11the data would still be protected in
- 00:16:13that case, right? So if you do
- 00:16:14authentication with middleware or your
- 00:16:17page component, you can still I think
- 00:16:19you can still keep doing that. But I
- 00:16:21would build in some kind of data access
- 00:16:23layer. So if there is some request going
- 00:16:26to the database or to interact with my
- 00:16:27data, there is like an additional check
- 00:16:30to see if the user should have access or
- 00:16:33not. Now I can then use that a function
- 00:16:36from my data access layer not only in a
- 00:16:39server component, right? So I used it
- 00:16:40here in the documents list, but I could
- 00:16:42also use this function in a server
- 00:16:44action, let's say, or in a route
- 00:16:46handler, right? So my entire Nex.js
- 00:16:49server side would then only use
- 00:16:51functions for my Dell data access layer,
- 00:16:54right? So maybe you have a server action
- 00:16:56and a server action in Next.js is
- 00:16:58basically just a post API endpoint. It
- 00:17:01has some built-in security, but
- 00:17:02technically somebody could perhaps be
- 00:17:05able to trigger this uh function to run
- 00:17:07on the server. We do want to have an
- 00:17:09authentication check here if only logged
- 00:17:10in users should be able to access this.
- 00:17:13You may forget that, right? Oops, I
- 00:17:15forgot to do that. So that's potentially
- 00:17:16a problem because here we are
- 00:17:18interacting with our database again. But
- 00:17:20if we have a Dell function that we can
- 00:17:23use instead and all of them have that
- 00:17:25authentication check built in then as
- 00:17:27long as we just use that and we don't
- 00:17:29use Prisma in here then even if we
- 00:17:31forget to do authentication in here
- 00:17:33since this function right before we
- 00:17:35access our data still has the O check in
- 00:17:37here we would still be saved by that. So
- 00:17:39we can use those Dell functions anywhere
- 00:17:41in our app actually not just in server
- 00:17:44components but also server actions and
- 00:17:46these API route handler. So with this
- 00:17:48data access layer we built a more robust
- 00:17:51resilient app protecting better against
- 00:17:54potential developer error and also
- 00:17:56removes a lot of stress actually because
- 00:17:58maybe you were thinking oh where should
- 00:17:59I do authentication or did I really
- 00:18:02protect that route or not? Well you have
- 00:18:04a little bit more safety now. The only
- 00:18:05downside that I found so far with Adele
- 00:18:08is if you have a page that you want to
- 00:18:11protect, but the page should stay
- 00:18:12statically rendered. So the downside
- 00:18:15with this is that um with your
- 00:18:17authentication solution is most likely
- 00:18:19just going to use the cookies and
- 00:18:20headers of the incoming request and that
- 00:18:23can only happen during runtime. So as
- 00:18:25the request comes in, it needs to check
- 00:18:26the cookies. So if you have some kind of
- 00:18:28authentication check on /document in the
- 00:18:31page component or you're using a
- 00:18:33function from Dell with the
- 00:18:34authentication check built in that
- 00:18:36slashdocument route is going to be
- 00:18:39dynamically rendered. It's going to be
- 00:18:40opted out of static rendering. However,
- 00:18:42if you only use middleware for
- 00:18:44authentication in that case the route
- 00:18:46can actually stay statically rendered.
- 00:18:48So from my understanding you can only
- 00:18:50leave the route statically rendered with
- 00:18:52middleware authentication only. So if
- 00:18:54you have some kind of content website or
- 00:18:56some kind of gated content, something
- 00:18:58that needs some static data that needs
- 00:19:01to be protected, it may be a problem
- 00:19:03because it's going to turn it into a
- 00:19:04dynamically rendered page. So in that
- 00:19:06case, from my from my personal
- 00:19:08understanding can do authentication in
- 00:19:10middleware and in that case it can stay
- 00:19:12statically rendered. But for all other
- 00:19:14cases, I would uh I would use a Dell.
- 00:19:17Right? So again this is just a simple
- 00:19:18example. I could also add other rules
- 00:19:20here like the roles and permissions.
- 00:19:22Right? So if we only want to allow admin
- 00:19:24users to get all the secret documents,
- 00:19:26we could build that in here. And as long
- 00:19:28as we use this function throughout our
- 00:19:29application, that should be fine. So
- 00:19:32let's talk about some uh tips here or
- 00:19:34maybe some things to pay attention to.
- 00:19:36So we only want to use these functions
- 00:19:38now to to interact with our database,
- 00:19:40right? So we do need to sort of enforce
- 00:19:42that if the developer in the app is
- 00:19:45going to do something with data that
- 00:19:47they use these functions because these
- 00:19:49all have the authentication check,
- 00:19:50right? So we don't want to have a
- 00:19:52developer on our team or AI right so in
- 00:19:55a component like this here we are
- 00:19:57properly using that function from the
- 00:19:58Dell but you can imagine that if you're
- 00:20:00using AI right so maybe using some kind
- 00:20:02of AI co-pilot and they're really good
- 00:20:05actually but sometimes they make some
- 00:20:06mistakes so one of them could
- 00:20:07technically do something like this right
- 00:20:10this is what they often this this is
- 00:20:12what they've seen in a lot of code and
- 00:20:13so they could actually still use Prisma
- 00:20:15and and not use the function from the
- 00:20:17Dell are there maybe some ways that we
- 00:20:19can sort of enforce force it to use uh
- 00:20:22only functions from here. Now when you
- 00:20:23think of it, we basically don't want to
- 00:20:25see Prisma outside this file right now.
- 00:20:28So we can maybe set up an ESLint rule.
- 00:20:31So we get a warning if we try to use
- 00:20:33Prisma outside this file. So we actually
- 00:20:35have an ESLint file here as part of the
- 00:20:38default next.js setup. And eslint
- 00:20:40linting is basically just checking if
- 00:20:42you are conforming to some style or some
- 00:20:45convention. And you can create your own
- 00:20:47rules. Now I've been trying some things.
- 00:20:49I'm not an ESLint expert unfortunately,
- 00:20:52so I can't guarantee that this is 100%
- 00:20:54correct. So it could be something like
- 00:20:56this. Uh and basically it will check for
- 00:20:58all of these files to see if you have
- 00:21:00some kind of import like this, right?
- 00:21:02Except for the actual Dell layer where
- 00:21:04we actually do want to allow that,
- 00:21:06right? So then for example um if you
- 00:21:08were trying to import from at lib.db
- 00:21:12outside the Dell layer, we would get
- 00:21:13that warning here from ESLint. Right?
- 00:21:15also here um if you try to import from
- 00:21:18at Prisma client directly you would also
- 00:21:21get that warning here and so you could
- 00:21:22set up something like this also in your
- 00:21:24CI/CD pipeline now about the Dell folder
- 00:21:27structure I just have one uh file here
- 00:21:30well where is the Prisma variable here
- 00:21:32coming from well actually I set up
- 00:21:34Prisma in a separate file here in a
- 00:21:37library folder this is a code snippet
- 00:21:40that Prisma gives on the website this is
- 00:21:42basically where the Prisma client is
- 00:21:44being instantiated so the idea is that
- 00:21:46you instantiate it once for your whole
- 00:21:47app and then you would just uh import
- 00:21:49this variable to use it. So you're not
- 00:21:51necessarily instantiating it over and
- 00:21:53over again. So that's why they have the
- 00:21:55snippet. Now in this case I only I don't
- 00:21:57want to use it in all parts of my app. I
- 00:21:59only want to use it in this file let's
- 00:22:01say or only in the Dell folder. So I
- 00:22:03could actually also just uh instantiate
- 00:22:07it right here in this file. Something
- 00:22:09like this. And actually just for
- 00:22:11simplicity here as an example this is
- 00:22:14what it would look like. So now I would
- 00:22:15not be using Prisma as an import. I
- 00:22:17would actually delete it to be uh to be
- 00:22:20certain. And now Prisma is only
- 00:22:22available in this file this variable.
- 00:22:24I'm not exporting. Right? So now if you
- 00:22:26try using Prisma, you will get a warning
- 00:22:29here. There is no lip dB anymore. So if
- 00:22:31I remove that, now I get a warning.
- 00:22:33Prisma Prisma cannot be I cannot just
- 00:22:35import it here. Right? There's no export
- 00:22:38with the Prisma variable like that. It's
- 00:22:40only available internally here. Right?
- 00:22:42And again, you need to take a look at
- 00:22:43how Prisma recommends that you set it up
- 00:22:45in Nex.js. So, there may be a better way
- 00:22:47of doing this, but uh this may be
- 00:22:50something to take a look at. Now, about
- 00:22:51the Dell folder structure, I just have
- 00:22:54one uh file here, but you can also do it
- 00:22:56differently, right? So, you have maybe
- 00:22:58uh a folder for secret document, for a
- 00:23:00table, and then you could have let's say
- 00:23:02one file for all your queries. So, we
- 00:23:04would have get all documents, get by ID,
- 00:23:08all your reads essentially. And then you
- 00:23:09would have your mutations. So all your
- 00:23:11rights, editing, deleting, adding
- 00:23:14something you would have that in this
- 00:23:16file. Now by the way on a side note for
- 00:23:18the types actually depending on your OM
- 00:23:21but at least with Prisma when you
- 00:23:22generate the client based on your
- 00:23:24schema. So my secret documents are
- 00:23:27structured like this with an ID and
- 00:23:29content and so on. When you want to
- 00:23:30allow users to create a secret document,
- 00:23:33they do not have to specify an ID,
- 00:23:35right? Because it's not created yet. So
- 00:23:37it wouldn't make sense to add an ID. So
- 00:23:39that can actually complicate the types a
- 00:23:41little bit because it's not just a type
- 00:23:43of uh secret document, right? Because a
- 00:23:46secret document type um also would have
- 00:23:48the ID, right? And we don't want to
- 00:23:49force that when we create one. So that
- 00:23:51complicates things a little bit, but
- 00:23:53Prisma actually automatically generate
- 00:23:55types from this as well that you can use
- 00:23:58in your application to type these sorts
- 00:24:00of functions actually very easily. So
- 00:24:02here for example, it has a type for
- 00:24:04creating a document. So then the ID is
- 00:24:07actually optional, right? So that that
- 00:24:08makes sense. Actually quite an
- 00:24:10underrated feature. Now one other thing
- 00:24:11I should mention as well is here I'm
- 00:24:14redirecting always to the login page.
- 00:24:17Now this is probably not ideal because
- 00:24:19we don't know exactly where this
- 00:24:21function will be called. There may be
- 00:24:22some cases where we call this function
- 00:24:25and if it turns out the user is not
- 00:24:26logged in, we actually don't want to
- 00:24:28redirect. We want to do something else.
- 00:24:30Maybe we're calling this in an API
- 00:24:32route. For example, if the user is not
- 00:24:34logged in, we just want to return like a
- 00:24:3640 like a 401 error. But now this would
- 00:24:39redirect the user all of a sudden,
- 00:24:41right? So we may want to allow the
- 00:24:43caller of the function to decide what to
- 00:24:46do with it. So perhaps uh you want to
- 00:24:48throw an error, right? Um so then if you
- 00:24:51use that function, you would have a try
- 00:24:53catch around here and then when you
- 00:24:54catch an error, you can check what type
- 00:24:56of error it is or what the message is
- 00:24:58and then still redirect if in case you
- 00:25:01want to do that. You can also abstract.
- 00:25:03You can then also abstract that away in
- 00:25:05some utility functions. So now we don't
- 00:25:07want to run these functions on the
- 00:25:08client side. So this is all server side
- 00:25:10code. It should stay on the server side.
- 00:25:12So there is a utility package that we
- 00:25:14can use here called server
- 00:25:16only. We can import it like this. And I
- 00:25:19can install it like this. Right? So this
- 00:25:20is different from server actions. Right?
- 00:25:22Server actions have use server. That's
- 00:25:24actually really powerful. This is more
- 00:25:26like a quick utility that we can add
- 00:25:29here. So if you try to use this from a
- 00:25:32client component for example, you will
- 00:25:34get an error. Now maybe you're worried
- 00:25:36about performance because on one page
- 00:25:39you could have lots of components that
- 00:25:41need data and so you may use a lot of
- 00:25:44these functions on each page and so you
- 00:25:46may be worried that you're going to do
- 00:25:47an authentication check many times
- 00:25:48before you actually have finished
- 00:25:50rendering the page. Well, that's not
- 00:25:52necessarily a problem. So here actually
- 00:25:54in the next documentation they also show
- 00:25:56you an example of a data access layer.
- 00:25:58And here they actually have an example
- 00:25:59with the react cache function. So this
- 00:26:02is react actually not next.js but
- 00:26:04basically if there's an incoming request
- 00:26:06to your server side and you're going to
- 00:26:08render out that page the function that
- 00:26:10should only run once during that render
- 00:26:12pass in cache here. So then rendering of
- 00:26:15the page it's only going to run that
- 00:26:17code once and reuse that result and when
- 00:26:19the request has finished the next time
- 00:26:21it would uh check the authentication
- 00:26:23again. So if you're a little bit
- 00:26:24confused I think that's totally normal.
- 00:26:26It's a complicated topic, but hopefully
- 00:26:28it helps you out. I want to thank you
- 00:26:29for watching. I want to thank Kind for
- 00:26:31sponsoring the video. Make sure to check
- 00:26:32them out. You can find a link in the
- 00:26:33description. They actually have a
- 00:26:35wonderful solution here. Instead of
- 00:26:36doing authentication myself, a lot of
- 00:26:38people think authentication is just oh,
- 00:26:40it's just user email and password,
- 00:26:42right? And actually, no, there's way
- 00:26:43more to it. You get a massive feature
- 00:26:45set out of the box, including roles and
- 00:26:47permissions and way more. But recently,
- 00:26:49they have now also released their
- 00:26:51workflows feature. So, you get a lot of
- 00:26:53things out of the box, but still
- 00:26:54customize many things. In any case,
- 00:26:56thank you for watching and I hope to see
- 00:26:58you the next one.
- Next.js
- authentification
- middleware
- données sensibles
- sécurité
- couche d'accès aux données
- Prisma
- développement web
- ESLint
- recommandations de sécurité