Always Use DAL Authentication In Next.js (Data Access Layer)

00:26:59
https://www.youtube.com/watch?v=mCmwqhvsyUg

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.

Mostrar mais

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

Obtenha acesso instantâneo a resumos gratuitos de vídeos do YouTube com tecnologia de IA!
Legendas
en
Rolagem automática:
  • 00:00:00
    Everyone, let's talk a little bit more
  • 00:00:01
    about authentication in Nex.js.
  • 00:00:03
    Unfortunately, recently there has been
  • 00:00:05
    an issue with middleware in Nex.js where
  • 00:00:09
    it may have been possible that some
  • 00:00:11
    attacker could have been able to bypass
  • 00:00:14
    middleware. So, if you were only doing
  • 00:00:16
    the authentication check in middleware,
  • 00:00:18
    that could potentially have been a
  • 00:00:19
    problem. So, I've seen some people
  • 00:00:21
    wonder about how to do authentication.
  • 00:00:23
    Should you still do it in middleware or
  • 00:00:25
    only in the page component or how to how
  • 00:00:27
    to structure everything? So, I want to
  • 00:00:30
    talk about it in this video, but I can
  • 00:00:31
    already tell you that you probably want
  • 00:00:33
    to look into a so-called data access
  • 00:00:36
    layer. I've mentioned it before, and
  • 00:00:38
    this is also something that is
  • 00:00:39
    recommended here by the Nex.js team
  • 00:00:42
    themselves. And by using a data access
  • 00:00:44
    layer, you can build much more robust
  • 00:00:46
    Nex.js applications. So, I want to dive
  • 00:00:49
    a little bit deeper into a data access
  • 00:00:51
    layer and look at some tips and tricks.
  • 00:00:53
    So, let's quickly recap with why we even
  • 00:00:56
    want this. What is wrong with just doing
  • 00:00:57
    authentication in middleware or the p or
  • 00:01:00
    page component? Because that's probably
  • 00:01:02
    what you've been using so far. Either
  • 00:01:04
    middleware or you do it directly in the
  • 00:01:05
    page component. But there are some
  • 00:01:07
    pitfalls. So let's take a look at an
  • 00:01:09
    example. We have a super simple app for
  • 00:01:12
    storing secret documents. The secret
  • 00:01:14
    documents fault. And you can view the
  • 00:01:17
    documents on the route/ documents. Here
  • 00:01:20
    we have three documents but they are top
  • 00:01:22
    secret. So we need to protect this data.
  • 00:01:25
    So if we zoom out a little bit and take
  • 00:01:27
    a look at how a nextjs app is typically
  • 00:01:29
    structured. Basically this entire thing
  • 00:01:32
    here is one next.js app. We have a
  • 00:01:34
    client side as well as a server side.
  • 00:01:36
    And we also have something called
  • 00:01:38
    middleware. Right? So if we send a
  • 00:01:39
    request from the client side to the
  • 00:01:41
    server side, we can let it go through
  • 00:01:42
    middleware first and then we can do
  • 00:01:45
    other stuff. Right? So the recent
  • 00:01:46
    security vulnerability basically had to
  • 00:01:49
    do with bypassing middleware that should
  • 00:01:51
    have been resolved. Now what we want to
  • 00:01:53
    protect is the data, right? So the data
  • 00:01:56
    is the most important thing. So if a
  • 00:01:58
    user is able to change something in the
  • 00:02:00
    UI or rerender the wrong button, let's
  • 00:02:03
    say, all of that is not really a huge
  • 00:02:06
    issue as long as the user is not able to
  • 00:02:08
    get access to data that they should not
  • 00:02:11
    have access to. Right? So the data is
  • 00:02:13
    really I would say the core part that we
  • 00:02:15
    really need to protect. Everything else
  • 00:02:17
    around it is essentially just UI. In
  • 00:02:19
    this case, we have secret documents. So
  • 00:02:21
    this content here could be you know very
  • 00:02:24
    could be top secret right could be could
  • 00:02:26
    be the launch codes we need to be really
  • 00:02:28
    careful with who gets access to this and
  • 00:02:30
    right now it's a public route everybody
  • 00:02:33
    can go here right so if I go to the
  • 00:02:35
    homepage this is a public route and in
  • 00:02:37
    nextg we have uh well the pagets access
  • 00:02:40
    right here right just the homepage okay
  • 00:02:42
    and then we have that documents route
  • 00:02:44
    which should absolutely not be publicly
  • 00:02:46
    accessible but right now it is we have
  • 00:02:48
    that right here what am I doing in this
  • 00:02:50
    page Well, I'm just grabbing all the
  • 00:02:52
    documents from my database. I'm just
  • 00:02:54
    using Prisma here, but works the same
  • 00:02:55
    with any other OM or whatever you're
  • 00:02:57
    using to access your database. And here
  • 00:02:59
    I get all the secret documents and I'm
  • 00:03:01
    just mapping over them here. So for each
  • 00:03:03
    one, I'm just uh creating some markup
  • 00:03:05
    here. And here you can see I'm
  • 00:03:07
    outputting doc.content. That's some
  • 00:03:09
    really sensitive data that we should not
  • 00:03:12
    be just loosely throwing around. So how
  • 00:03:16
    would we protect this route? Let's say
  • 00:03:18
    we have a very simple authentication
  • 00:03:19
    strategy. We only want to allow logged
  • 00:03:23
    in users to access this data. Right? So
  • 00:03:26
    when I say logged in, it basically just
  • 00:03:28
    means that they have some valid access
  • 00:03:31
    token. Right? Typically we have
  • 00:03:32
    so-called session. So if as long as the
  • 00:03:34
    user can keep showing a valid access
  • 00:03:36
    token which can be a JSON web token JWT
  • 00:03:39
    typically stored in a cookie and so then
  • 00:03:43
    on every request to the server side that
  • 00:03:45
    cookie will be sent with it and so let's
  • 00:03:48
    try to protect this route so that only
  • 00:03:50
    logged in users can access it. So for
  • 00:03:52
    authentication typically you have
  • 00:03:54
    probably used the page components in
  • 00:03:57
    nextJS which are just server components
  • 00:03:59
    or you've been doing it in middleware.
  • 00:04:01
    These are the two common approaches.
  • 00:04:03
    Now, what I want to show you in this
  • 00:04:05
    video is actually that doing it in
  • 00:04:07
    either of these two is actually not
  • 00:04:08
    going to be sufficient in most cases.
  • 00:04:11
    You you should view this more as your
  • 00:04:12
    first line of defense, but you want to
  • 00:04:14
    have a so-called data access layer in
  • 00:04:16
    addition to that to make it more robust.
  • 00:04:19
    So, let's try to protect this like how
  • 00:04:21
    you would traditionally perhaps uh start
  • 00:04:23
    off. Well, you would do it either
  • 00:04:25
    directly here in the page or you would
  • 00:04:27
    create a middleware file and do it in
  • 00:04:29
    middleware. But let's say we do it in
  • 00:04:31
    the page component here. So I need some
  • 00:04:32
    kind of authentication solution and I
  • 00:04:34
    will use KINT in this video. I'm a brand
  • 00:04:36
    ambassador for Kind. It's a paid
  • 00:04:38
    sponsorship but had a great time working
  • 00:04:40
    with them. But the things we talk about
  • 00:04:41
    here are relevant for the other
  • 00:04:42
    solutions you may be using as well. So
  • 00:04:44
    no matter what authentication solution
  • 00:04:46
    you use, what we talk about here is
  • 00:04:48
    relevant for all of them. So in this
  • 00:04:49
    case, I like using Kite. Super fast to
  • 00:04:51
    set up. I have other videos with them.
  • 00:04:53
    If you want me to walk you through how
  • 00:04:54
    to set it up, I have other videos with
  • 00:04:56
    Kite. Make sure to check them out. But
  • 00:04:57
    basically any authentication solution
  • 00:04:59
    will allow you to check the incoming
  • 00:05:01
    request to see if the user is logged in
  • 00:05:04
    or not. So if the user is not logged in
  • 00:05:05
    typically we do want to redirect them to
  • 00:05:08
    the login page. This is the route I can
  • 00:05:10
    redirect to. By the way, Nexj has a
  • 00:05:12
    redirect and works by throwing an error.
  • 00:05:15
    So if the code reaches this line, it
  • 00:05:17
    will throw an error. It will not
  • 00:05:19
    continue down here. Right? So if you
  • 00:05:21
    really want to be explicit about it uh
  • 00:05:23
    because it's unreachable code. Okay.
  • 00:05:25
    Okay. So this is how a lot of people do
  • 00:05:27
    it and it's not inherently bad. So now
  • 00:05:29
    we have homepage as public. Now if I try
  • 00:05:31
    to go to /documents, it should be
  • 00:05:33
    protected, right? So let's see what we
  • 00:05:35
    get and waiting. Yeah. So now indeed I
  • 00:05:37
    cannot access it. I'm not logged in. I'm
  • 00:05:39
    redirected here to a login page. So this
  • 00:05:42
    is now properly protecting the data. So
  • 00:05:45
    this is the default login page I get
  • 00:05:47
    with kind. I can decide how users can
  • 00:05:49
    login. So in this case I enabled uh
  • 00:05:51
    GitHub login. But here are all the other
  • 00:05:53
    options I have as well. So I can add
  • 00:05:55
    phone, username and code, username,
  • 00:05:57
    email and password and other social
  • 00:05:59
    connections as well. All from the
  • 00:06:01
    dashboard here in kind. Really nice.
  • 00:06:02
    They now also allow you to design a
  • 00:06:04
    custom login page. They even help you
  • 00:06:06
    out with some nice templates here as
  • 00:06:07
    well. So you can pretty much customize
  • 00:06:09
    this almost in any way you want. All
  • 00:06:11
    right, but let me actually log in here
  • 00:06:12
    and see if our app is still working. All
  • 00:06:14
    right, so I just logged in and I'm being
  • 00:06:16
    redirected here to the homepage. Now if
  • 00:06:18
    I go to slash uh documents, let's see
  • 00:06:21
    what we get. All right. So now I can see
  • 00:06:24
    the data again. It is protected now and
  • 00:06:26
    I can still access it because now I am
  • 00:06:29
    logged in. Meaning I have these tokens,
  • 00:06:32
    right? Particularly the access token
  • 00:06:34
    which is just a JSON web token. As long
  • 00:06:37
    as I can show this and it's still valid,
  • 00:06:39
    I can access the data right now. Now
  • 00:06:40
    what is the risk with this? Because this
  • 00:06:43
    is how a lot of people do it actually.
  • 00:06:44
    Well, the biggest risk is that over time
  • 00:06:47
    you will switch up your code. The way
  • 00:06:50
    that we do it right here is we fetch the
  • 00:06:51
    data also directly here on the page and
  • 00:06:55
    then uh we map over it here on the page.
  • 00:06:57
    But typically you structure your react
  • 00:07:00
    applications a bit differently. For
  • 00:07:01
    example, you often create dedicated
  • 00:07:04
    component. So for this list for example,
  • 00:07:06
    we could create a dedicated component
  • 00:07:08
    called documents list in the components
  • 00:07:11
    folder or wherever. I can create a
  • 00:07:13
    component. Let's just call it documents
  • 00:07:14
    list. Let me remove that. Right? That's
  • 00:07:16
    typically how you structure React
  • 00:07:18
    applications. You want to have nice,
  • 00:07:20
    clean, reusable components. That's one
  • 00:07:24
    of the reasons why React became so
  • 00:07:25
    popular. It's because uh you were able
  • 00:07:27
    to reason about your application as a
  • 00:07:29
    tree of components. Now I have the
  • 00:07:31
    markup here now, but it needs the data
  • 00:07:33
    here, right? So I could pass it as a
  • 00:07:35
    prop, right? So we will have our
  • 00:07:37
    component here. Now we could pass it as
  • 00:07:39
    a prop, but we can also fetch data
  • 00:07:42
    directly in this in a React server
  • 00:07:44
    component. Right? Right. So in nextJS we
  • 00:07:46
    can mark it as async a server component
  • 00:07:48
    and then just get data directly reach
  • 00:07:50
    out to our database directly like like
  • 00:07:53
    this not only on the page component we
  • 00:07:55
    can do that in any react server
  • 00:07:57
    component. So I could also do that in
  • 00:07:59
    here and actually there are some good
  • 00:08:00
    arguments to be made to do it in here.
  • 00:08:03
    So I can just mark this as async as
  • 00:08:05
    well. I can fetch the data in my react
  • 00:08:08
    server component like this. Right? So
  • 00:08:09
    now I don't even have to pass a prop.
  • 00:08:11
    And now my app is structured like this.
  • 00:08:13
    And there are some good arguments to be
  • 00:08:14
    made to do it this way actually because
  • 00:08:17
    you can now also wrap it in suspense. So
  • 00:08:19
    then you can show a fallback as this is
  • 00:08:21
    fetching the data and we're waiting for
  • 00:08:23
    it for it to finish. Right? And there
  • 00:08:25
    are some other reasons but we can get
  • 00:08:26
    rid of Prisma here because we are not
  • 00:08:28
    using Prisma in this file anymore. All
  • 00:08:30
    right. Now what you could say what is
  • 00:08:31
    the problem? We still have
  • 00:08:33
    authentication here in this page right
  • 00:08:35
    this component. Yeah. Okay. Now it's
  • 00:08:36
    sitting in a different file but
  • 00:08:38
    everything here is still protected.
  • 00:08:39
    Right? If we go to this page it will
  • 00:08:42
    still run. If we go to this page, if
  • 00:08:44
    somebody goes here, it will still run
  • 00:08:45
    this code first before we get to here.
  • 00:08:48
    So, this is all uh this is all safe,
  • 00:08:50
    right? Well, now what could happen is
  • 00:08:53
    you or somebody else on your team or
  • 00:08:55
    importantly AI, right? An insane amount
  • 00:08:58
    of code these days is being generated
  • 00:09:00
    with AI and AI is really good and it is
  • 00:09:03
    still getting better of course, but
  • 00:09:05
    sometimes if it's if it's if something
  • 00:09:07
    is really tricky, it may not do it
  • 00:09:09
    properly. So what could happen is that
  • 00:09:11
    somebody could reuse this component
  • 00:09:14
    because that's what we do with React
  • 00:09:16
    components very often. We reuse them. So
  • 00:09:19
    somebody could use that on some other
  • 00:09:20
    page. Let's say the homepage or any uh
  • 00:09:23
    public page. Maybe somebody's like, "Oh,
  • 00:09:25
    we need a documents list here." I can
  • 00:09:27
    just reuse that component. But now this
  • 00:09:30
    page does not have an authentication
  • 00:09:31
    check. If I log out here, let me
  • 00:09:33
    actually also add a log out button. So
  • 00:09:36
    kind just gives me this log out link. So
  • 00:09:38
    then if I click there, it will clear out
  • 00:09:40
    my cookies and just log log me out. And
  • 00:09:43
    you can see I'm redirected now to the
  • 00:09:45
    homepage. But what do I see on this
  • 00:09:47
    public homepage? I see the launch codes.
  • 00:09:50
    I see all these secret documents. This
  • 00:09:52
    is now publicly available. And I would
  • 00:09:54
    say this is a reasonable risk. I
  • 00:09:57
    wouldn't say it's extremely likely that
  • 00:09:58
    it's going to happen, but it's still
  • 00:10:00
    likely enough that you need to have some
  • 00:10:03
    kind of safeguard against this. So what
  • 00:10:05
    is the reason this could happen? Well,
  • 00:10:07
    it's because the place where we are
  • 00:10:09
    doing the authentication check, where we
  • 00:10:11
    are accessing data, those two things are
  • 00:10:13
    in different places, right? They are in
  • 00:10:15
    different files. They're in different
  • 00:10:16
    places. So, there is a gap between the
  • 00:10:18
    authentication check and where we access
  • 00:10:21
    our data. And because of that gap, there
  • 00:10:23
    is some risk that something sort of gets
  • 00:10:26
    in that gap. Well, in this case, what
  • 00:10:27
    happened is where we access the data, we
  • 00:10:30
    reuse that on some other place in some
  • 00:10:32
    other place where there was no
  • 00:10:33
    authentication check before there. Now,
  • 00:10:35
    of course, you can you can prevent this
  • 00:10:37
    by making sure that you always do the
  • 00:10:40
    authentication check before you access
  • 00:10:43
    data. I could technically try to add it
  • 00:10:45
    here, but it makes more sense to have a
  • 00:10:47
    dedicated uh place in your app. So, that
  • 00:10:49
    was an example with the page component,
  • 00:10:50
    but maybe you were wondering about
  • 00:10:52
    middleware. So, we could technically
  • 00:10:53
    also do authentication in middleware.
  • 00:10:55
    So, with kind, I can uh wrap the request
  • 00:10:57
    with with O. Now, client will give you
  • 00:11:00
    the path that they recommend to use. But
  • 00:11:02
    just as an example here, let's say I
  • 00:11:04
    only want to protect the slashdocuments
  • 00:11:07
    route, right? You would do something
  • 00:11:08
    like this, right? So it it would match
  • 00:11:10
    for the slash document because on the
  • 00:11:11
    slash documents route, we had that
  • 00:11:14
    secret data, right? But now what
  • 00:11:16
    happened was with re with react, we
  • 00:11:18
    actually put the data in a react
  • 00:11:20
    component and then we reused that on the
  • 00:11:22
    homepage and the homepage you can see
  • 00:11:25
    here in middleware is also not
  • 00:11:26
    protected. So we would have the same
  • 00:11:28
    issue whether you use middleware or you
  • 00:11:30
    do authentication directly in the page
  • 00:11:32
    component it would be the same result
  • 00:11:33
    because you could technically reuse that
  • 00:11:35
    component on the homepage or any public
  • 00:11:37
    page and you can see we are not we are
  • 00:11:40
    not protecting right we don't we don't
  • 00:11:41
    have this as in our metro here we only
  • 00:11:44
    have / documents so we would have had
  • 00:11:45
    the same issue if we were using
  • 00:11:47
    middleware doing authentication in
  • 00:11:49
    middleware or in the page component
  • 00:11:51
    should probably only be your first line
  • 00:11:53
    of defense so ideally we can have a more
  • 00:11:55
    robust solution for is. So this is where
  • 00:11:58
    a data access layer comes into play. But
  • 00:12:01
    there are various ways that you can
  • 00:12:02
    implement a data access layer. I'm just
  • 00:12:04
    going to give you one example here. It's
  • 00:12:06
    basically a dedicated place where we do
  • 00:12:08
    all of our data access. So whenever we
  • 00:12:10
    reach out to our database, all of that
  • 00:12:12
    is going to go in here in one
  • 00:12:14
    centralized place. I can literally call
  • 00:12:16
    it data access or abbreviated Dell. Now
  • 00:12:19
    in this case, I only have one uh table
  • 00:12:22
    right in my database secret document. So
  • 00:12:24
    I could create uh a a file uh per table
  • 00:12:29
    let's say and then here all of the
  • 00:12:31
    operations that I want to do on that
  • 00:12:33
    table will be done with functions in
  • 00:12:36
    here. So for example I can have a
  • 00:12:38
    function to get all secret documents
  • 00:12:41
    right we can just call that get secret
  • 00:12:43
    documents or maybe even more explicit
  • 00:12:46
    get all secret documents and it will go
  • 00:12:48
    into my database and just return that.
  • 00:12:50
    And importantly remember why we had that
  • 00:12:52
    issue. This was it was because there was
  • 00:12:54
    a gap between where we do the O check
  • 00:12:56
    and where we access our data. So what I
  • 00:12:58
    could do here is I can include the
  • 00:13:01
    authentication check right in here. So
  • 00:13:03
    now there is no gap right before I
  • 00:13:05
    access my data. I'm first going to check
  • 00:13:08
    my authentication status. So that's for
  • 00:13:10
    getting all the secret documents. But
  • 00:13:11
    you can imagine uh we can have other
  • 00:13:13
    things like creating a secret document
  • 00:13:16
    or deleting one or editing one or all
  • 00:13:18
    your CRUD operations whatever you want
  • 00:13:20
    to do. But in my example here, I'm doing
  • 00:13:23
    an authentication check right before I
  • 00:13:25
    access the data. So now, as long as I
  • 00:13:28
    only use functions from this file, deal
  • 00:13:31
    with my data, I should be safe, right?
  • 00:13:34
    So let me see. So I removed the
  • 00:13:35
    middleware. So let's go back to our page
  • 00:13:38
    authentication. So let me actually
  • 00:13:39
    remove it from the homepage and let's
  • 00:13:41
    see what we had before. So on the slash
  • 00:13:43
    document, we have this uh documents
  • 00:13:45
    list. Here is where we were currently
  • 00:13:47
    getting the data. But but now we only
  • 00:13:49
    want to use functions from this file,
  • 00:13:52
    right? So only functions from my data
  • 00:13:55
    access layer. So in this case, if we
  • 00:13:57
    want to get all the secret documents, I
  • 00:13:59
    have to use this function. So I don't
  • 00:14:01
    want to see Prisma elsewhere in my app
  • 00:14:03
    anymore, right? I only want to see
  • 00:14:05
    Prisma in this file. We can even try to
  • 00:14:07
    set up an ESLint rule. I'll show that in
  • 00:14:08
    a second. If I want to get uh docu, if I
  • 00:14:11
    want to get data, I would use that
  • 00:14:12
    function, right? So I can remove the
  • 00:14:14
    Prisma import here as well. As long as I
  • 00:14:15
    use that. Now if I use this uh component
  • 00:14:18
    anywhere let's say on uh let's say on /
  • 00:14:21
    document right of course we already had
  • 00:14:23
    an authentication check we were saved
  • 00:14:25
    but let's say you actually forgot it
  • 00:14:27
    that's also possible you can simply
  • 00:14:28
    forget to add authentication to your
  • 00:14:30
    page um because honestly doing
  • 00:14:32
    authentication in the page is actually
  • 00:14:34
    quite uh messy. It's not you don't have
  • 00:14:37
    a clear overview of which pages are
  • 00:14:39
    protected. It's quite messy. So it's
  • 00:14:41
    possible that you simply forget it. So
  • 00:14:42
    let's say you have a page and you forget
  • 00:14:44
    to do authentication but you do include
  • 00:14:45
    your documents list component here.
  • 00:14:47
    Well, if I now go to /documents, you
  • 00:14:50
    will see that it is still protected. So
  • 00:14:52
    let's actually see. You can see I'm
  • 00:14:54
    still redirected now to the login page
  • 00:14:55
    because how are we getting data in
  • 00:14:57
    there? Well, it's using this Dell
  • 00:15:00
    function and in every Dell function I
  • 00:15:02
    have an authentication check. So before
  • 00:15:04
    I actually access data, it has a uh
  • 00:15:07
    authentication check. Even if I forgot
  • 00:15:09
    it here, I would still be protected.
  • 00:15:10
    That's why I said that authentication in
  • 00:15:12
    your page component or in middleware
  • 00:15:15
    that's more like a first line of
  • 00:15:16
    defense. Now how about that other issue?
  • 00:15:18
    If you actually reuse it on a public
  • 00:15:20
    route, right? So we have a homepage. If
  • 00:15:22
    I go here, I have a homepage here.
  • 00:15:24
    Remember this is a public route. So if I
  • 00:15:26
    go to the homepage, it's a public route.
  • 00:15:27
    Now what if somebody maybe you or an AI
  • 00:15:30
    reuses that component here documents
  • 00:15:32
    list. Now previously we leaked all the
  • 00:15:34
    data. But now if I add it to the
  • 00:15:36
    homepage here, you can see actually I'm
  • 00:15:38
    already being redirected. If I try to go
  • 00:15:40
    to the homepage now, it is actually uh
  • 00:15:42
    going to redirect me because this
  • 00:15:44
    documents list component to get the data
  • 00:15:47
    is using my Dell function and my Dell
  • 00:15:49
    function has the authentication check
  • 00:15:51
    right here. I was not logged in so I'm
  • 00:15:53
    being redirected, right? And if you were
  • 00:15:55
    using middleware, right, and you
  • 00:15:56
    accidentally added a documents list on
  • 00:15:59
    the homepage, which we would not protect
  • 00:16:01
    with middleware right now, that would
  • 00:16:03
    not be the end of the world because to
  • 00:16:05
    get data, it's using a function from my
  • 00:16:07
    data access layer and that has already
  • 00:16:09
    built in the authentication check. So
  • 00:16:11
    the data would still be protected in
  • 00:16:13
    that case, right? So if you do
  • 00:16:14
    authentication with middleware or your
  • 00:16:17
    page component, you can still I think
  • 00:16:19
    you can still keep doing that. But I
  • 00:16:21
    would build in some kind of data access
  • 00:16:23
    layer. So if there is some request going
  • 00:16:26
    to the database or to interact with my
  • 00:16:27
    data, there is like an additional check
  • 00:16:30
    to see if the user should have access or
  • 00:16:33
    not. Now I can then use that a function
  • 00:16:36
    from my data access layer not only in a
  • 00:16:39
    server component, right? So I used it
  • 00:16:40
    here in the documents list, but I could
  • 00:16:42
    also use this function in a server
  • 00:16:44
    action, let's say, or in a route
  • 00:16:46
    handler, right? So my entire Nex.js
  • 00:16:49
    server side would then only use
  • 00:16:51
    functions for my Dell data access layer,
  • 00:16:54
    right? So maybe you have a server action
  • 00:16:56
    and a server action in Next.js is
  • 00:16:58
    basically just a post API endpoint. It
  • 00:17:01
    has some built-in security, but
  • 00:17:02
    technically somebody could perhaps be
  • 00:17:05
    able to trigger this uh function to run
  • 00:17:07
    on the server. We do want to have an
  • 00:17:09
    authentication check here if only logged
  • 00:17:10
    in users should be able to access this.
  • 00:17:13
    You may forget that, right? Oops, I
  • 00:17:15
    forgot to do that. So that's potentially
  • 00:17:16
    a problem because here we are
  • 00:17:18
    interacting with our database again. But
  • 00:17:20
    if we have a Dell function that we can
  • 00:17:23
    use instead and all of them have that
  • 00:17:25
    authentication check built in then as
  • 00:17:27
    long as we just use that and we don't
  • 00:17:29
    use Prisma in here then even if we
  • 00:17:31
    forget to do authentication in here
  • 00:17:33
    since this function right before we
  • 00:17:35
    access our data still has the O check in
  • 00:17:37
    here we would still be saved by that. So
  • 00:17:39
    we can use those Dell functions anywhere
  • 00:17:41
    in our app actually not just in server
  • 00:17:44
    components but also server actions and
  • 00:17:46
    these API route handler. So with this
  • 00:17:48
    data access layer we built a more robust
  • 00:17:51
    resilient app protecting better against
  • 00:17:54
    potential developer error and also
  • 00:17:56
    removes a lot of stress actually because
  • 00:17:58
    maybe you were thinking oh where should
  • 00:17:59
    I do authentication or did I really
  • 00:18:02
    protect that route or not? Well you have
  • 00:18:04
    a little bit more safety now. The only
  • 00:18:05
    downside that I found so far with Adele
  • 00:18:08
    is if you have a page that you want to
  • 00:18:11
    protect, but the page should stay
  • 00:18:12
    statically rendered. So the downside
  • 00:18:15
    with this is that um with your
  • 00:18:17
    authentication solution is most likely
  • 00:18:19
    just going to use the cookies and
  • 00:18:20
    headers of the incoming request and that
  • 00:18:23
    can only happen during runtime. So as
  • 00:18:25
    the request comes in, it needs to check
  • 00:18:26
    the cookies. So if you have some kind of
  • 00:18:28
    authentication check on /document in the
  • 00:18:31
    page component or you're using a
  • 00:18:33
    function from Dell with the
  • 00:18:34
    authentication check built in that
  • 00:18:36
    slashdocument route is going to be
  • 00:18:39
    dynamically rendered. It's going to be
  • 00:18:40
    opted out of static rendering. However,
  • 00:18:42
    if you only use middleware for
  • 00:18:44
    authentication in that case the route
  • 00:18:46
    can actually stay statically rendered.
  • 00:18:48
    So from my understanding you can only
  • 00:18:50
    leave the route statically rendered with
  • 00:18:52
    middleware authentication only. So if
  • 00:18:54
    you have some kind of content website or
  • 00:18:56
    some kind of gated content, something
  • 00:18:58
    that needs some static data that needs
  • 00:19:01
    to be protected, it may be a problem
  • 00:19:03
    because it's going to turn it into a
  • 00:19:04
    dynamically rendered page. So in that
  • 00:19:06
    case, from my from my personal
  • 00:19:08
    understanding can do authentication in
  • 00:19:10
    middleware and in that case it can stay
  • 00:19:12
    statically rendered. But for all other
  • 00:19:14
    cases, I would uh I would use a Dell.
  • 00:19:17
    Right? So again this is just a simple
  • 00:19:18
    example. I could also add other rules
  • 00:19:20
    here like the roles and permissions.
  • 00:19:22
    Right? So if we only want to allow admin
  • 00:19:24
    users to get all the secret documents,
  • 00:19:26
    we could build that in here. And as long
  • 00:19:28
    as we use this function throughout our
  • 00:19:29
    application, that should be fine. So
  • 00:19:32
    let's talk about some uh tips here or
  • 00:19:34
    maybe some things to pay attention to.
  • 00:19:36
    So we only want to use these functions
  • 00:19:38
    now to to interact with our database,
  • 00:19:40
    right? So we do need to sort of enforce
  • 00:19:42
    that if the developer in the app is
  • 00:19:45
    going to do something with data that
  • 00:19:47
    they use these functions because these
  • 00:19:49
    all have the authentication check,
  • 00:19:50
    right? So we don't want to have a
  • 00:19:52
    developer on our team or AI right so in
  • 00:19:55
    a component like this here we are
  • 00:19:57
    properly using that function from the
  • 00:19:58
    Dell but you can imagine that if you're
  • 00:20:00
    using AI right so maybe using some kind
  • 00:20:02
    of AI co-pilot and they're really good
  • 00:20:05
    actually but sometimes they make some
  • 00:20:06
    mistakes so one of them could
  • 00:20:07
    technically do something like this right
  • 00:20:10
    this is what they often this this is
  • 00:20:12
    what they've seen in a lot of code and
  • 00:20:13
    so they could actually still use Prisma
  • 00:20:15
    and and not use the function from the
  • 00:20:17
    Dell are there maybe some ways that we
  • 00:20:19
    can sort of enforce force it to use uh
  • 00:20:22
    only functions from here. Now when you
  • 00:20:23
    think of it, we basically don't want to
  • 00:20:25
    see Prisma outside this file right now.
  • 00:20:28
    So we can maybe set up an ESLint rule.
  • 00:20:31
    So we get a warning if we try to use
  • 00:20:33
    Prisma outside this file. So we actually
  • 00:20:35
    have an ESLint file here as part of the
  • 00:20:38
    default next.js setup. And eslint
  • 00:20:40
    linting is basically just checking if
  • 00:20:42
    you are conforming to some style or some
  • 00:20:45
    convention. And you can create your own
  • 00:20:47
    rules. Now I've been trying some things.
  • 00:20:49
    I'm not an ESLint expert unfortunately,
  • 00:20:52
    so I can't guarantee that this is 100%
  • 00:20:54
    correct. So it could be something like
  • 00:20:56
    this. Uh and basically it will check for
  • 00:20:58
    all of these files to see if you have
  • 00:21:00
    some kind of import like this, right?
  • 00:21:02
    Except for the actual Dell layer where
  • 00:21:04
    we actually do want to allow that,
  • 00:21:06
    right? So then for example um if you
  • 00:21:08
    were trying to import from at lib.db
  • 00:21:12
    outside the Dell layer, we would get
  • 00:21:13
    that warning here from ESLint. Right?
  • 00:21:15
    also here um if you try to import from
  • 00:21:18
    at Prisma client directly you would also
  • 00:21:21
    get that warning here and so you could
  • 00:21:22
    set up something like this also in your
  • 00:21:24
    CI/CD pipeline now about the Dell folder
  • 00:21:27
    structure I just have one uh file here
  • 00:21:30
    well where is the Prisma variable here
  • 00:21:32
    coming from well actually I set up
  • 00:21:34
    Prisma in a separate file here in a
  • 00:21:37
    library folder this is a code snippet
  • 00:21:40
    that Prisma gives on the website this is
  • 00:21:42
    basically where the Prisma client is
  • 00:21:44
    being instantiated so the idea is that
  • 00:21:46
    you instantiate it once for your whole
  • 00:21:47
    app and then you would just uh import
  • 00:21:49
    this variable to use it. So you're not
  • 00:21:51
    necessarily instantiating it over and
  • 00:21:53
    over again. So that's why they have the
  • 00:21:55
    snippet. Now in this case I only I don't
  • 00:21:57
    want to use it in all parts of my app. I
  • 00:21:59
    only want to use it in this file let's
  • 00:22:01
    say or only in the Dell folder. So I
  • 00:22:03
    could actually also just uh instantiate
  • 00:22:07
    it right here in this file. Something
  • 00:22:09
    like this. And actually just for
  • 00:22:11
    simplicity here as an example this is
  • 00:22:14
    what it would look like. So now I would
  • 00:22:15
    not be using Prisma as an import. I
  • 00:22:17
    would actually delete it to be uh to be
  • 00:22:20
    certain. And now Prisma is only
  • 00:22:22
    available in this file this variable.
  • 00:22:24
    I'm not exporting. Right? So now if you
  • 00:22:26
    try using Prisma, you will get a warning
  • 00:22:29
    here. There is no lip dB anymore. So if
  • 00:22:31
    I remove that, now I get a warning.
  • 00:22:33
    Prisma Prisma cannot be I cannot just
  • 00:22:35
    import it here. Right? There's no export
  • 00:22:38
    with the Prisma variable like that. It's
  • 00:22:40
    only available internally here. Right?
  • 00:22:42
    And again, you need to take a look at
  • 00:22:43
    how Prisma recommends that you set it up
  • 00:22:45
    in Nex.js. So, there may be a better way
  • 00:22:47
    of doing this, but uh this may be
  • 00:22:50
    something to take a look at. Now, about
  • 00:22:51
    the Dell folder structure, I just have
  • 00:22:54
    one uh file here, but you can also do it
  • 00:22:56
    differently, right? So, you have maybe
  • 00:22:58
    uh a folder for secret document, for a
  • 00:23:00
    table, and then you could have let's say
  • 00:23:02
    one file for all your queries. So, we
  • 00:23:04
    would have get all documents, get by ID,
  • 00:23:08
    all your reads essentially. And then you
  • 00:23:09
    would have your mutations. So all your
  • 00:23:11
    rights, editing, deleting, adding
  • 00:23:14
    something you would have that in this
  • 00:23:16
    file. Now by the way on a side note for
  • 00:23:18
    the types actually depending on your OM
  • 00:23:21
    but at least with Prisma when you
  • 00:23:22
    generate the client based on your
  • 00:23:24
    schema. So my secret documents are
  • 00:23:27
    structured like this with an ID and
  • 00:23:29
    content and so on. When you want to
  • 00:23:30
    allow users to create a secret document,
  • 00:23:33
    they do not have to specify an ID,
  • 00:23:35
    right? Because it's not created yet. So
  • 00:23:37
    it wouldn't make sense to add an ID. So
  • 00:23:39
    that can actually complicate the types a
  • 00:23:41
    little bit because it's not just a type
  • 00:23:43
    of uh secret document, right? Because a
  • 00:23:46
    secret document type um also would have
  • 00:23:48
    the ID, right? And we don't want to
  • 00:23:49
    force that when we create one. So that
  • 00:23:51
    complicates things a little bit, but
  • 00:23:53
    Prisma actually automatically generate
  • 00:23:55
    types from this as well that you can use
  • 00:23:58
    in your application to type these sorts
  • 00:24:00
    of functions actually very easily. So
  • 00:24:02
    here for example, it has a type for
  • 00:24:04
    creating a document. So then the ID is
  • 00:24:07
    actually optional, right? So that that
  • 00:24:08
    makes sense. Actually quite an
  • 00:24:10
    underrated feature. Now one other thing
  • 00:24:11
    I should mention as well is here I'm
  • 00:24:14
    redirecting always to the login page.
  • 00:24:17
    Now this is probably not ideal because
  • 00:24:19
    we don't know exactly where this
  • 00:24:21
    function will be called. There may be
  • 00:24:22
    some cases where we call this function
  • 00:24:25
    and if it turns out the user is not
  • 00:24:26
    logged in, we actually don't want to
  • 00:24:28
    redirect. We want to do something else.
  • 00:24:30
    Maybe we're calling this in an API
  • 00:24:32
    route. For example, if the user is not
  • 00:24:34
    logged in, we just want to return like a
  • 00:24:36
    40 like a 401 error. But now this would
  • 00:24:39
    redirect the user all of a sudden,
  • 00:24:41
    right? So we may want to allow the
  • 00:24:43
    caller of the function to decide what to
  • 00:24:46
    do with it. So perhaps uh you want to
  • 00:24:48
    throw an error, right? Um so then if you
  • 00:24:51
    use that function, you would have a try
  • 00:24:53
    catch around here and then when you
  • 00:24:54
    catch an error, you can check what type
  • 00:24:56
    of error it is or what the message is
  • 00:24:58
    and then still redirect if in case you
  • 00:25:01
    want to do that. You can also abstract.
  • 00:25:03
    You can then also abstract that away in
  • 00:25:05
    some utility functions. So now we don't
  • 00:25:07
    want to run these functions on the
  • 00:25:08
    client side. So this is all server side
  • 00:25:10
    code. It should stay on the server side.
  • 00:25:12
    So there is a utility package that we
  • 00:25:14
    can use here called server
  • 00:25:16
    only. We can import it like this. And I
  • 00:25:19
    can install it like this. Right? So this
  • 00:25:20
    is different from server actions. Right?
  • 00:25:22
    Server actions have use server. That's
  • 00:25:24
    actually really powerful. This is more
  • 00:25:26
    like a quick utility that we can add
  • 00:25:29
    here. So if you try to use this from a
  • 00:25:32
    client component for example, you will
  • 00:25:34
    get an error. Now maybe you're worried
  • 00:25:36
    about performance because on one page
  • 00:25:39
    you could have lots of components that
  • 00:25:41
    need data and so you may use a lot of
  • 00:25:44
    these functions on each page and so you
  • 00:25:46
    may be worried that you're going to do
  • 00:25:47
    an authentication check many times
  • 00:25:48
    before you actually have finished
  • 00:25:50
    rendering the page. Well, that's not
  • 00:25:52
    necessarily a problem. So here actually
  • 00:25:54
    in the next documentation they also show
  • 00:25:56
    you an example of a data access layer.
  • 00:25:58
    And here they actually have an example
  • 00:25:59
    with the react cache function. So this
  • 00:26:02
    is react actually not next.js but
  • 00:26:04
    basically if there's an incoming request
  • 00:26:06
    to your server side and you're going to
  • 00:26:08
    render out that page the function that
  • 00:26:10
    should only run once during that render
  • 00:26:12
    pass in cache here. So then rendering of
  • 00:26:15
    the page it's only going to run that
  • 00:26:17
    code once and reuse that result and when
  • 00:26:19
    the request has finished the next time
  • 00:26:21
    it would uh check the authentication
  • 00:26:23
    again. So if you're a little bit
  • 00:26:24
    confused I think that's totally normal.
  • 00:26:26
    It's a complicated topic, but hopefully
  • 00:26:28
    it helps you out. I want to thank you
  • 00:26:29
    for watching. I want to thank Kind for
  • 00:26:31
    sponsoring the video. Make sure to check
  • 00:26:32
    them out. You can find a link in the
  • 00:26:33
    description. They actually have a
  • 00:26:35
    wonderful solution here. Instead of
  • 00:26:36
    doing authentication myself, a lot of
  • 00:26:38
    people think authentication is just oh,
  • 00:26:40
    it's just user email and password,
  • 00:26:42
    right? And actually, no, there's way
  • 00:26:43
    more to it. You get a massive feature
  • 00:26:45
    set out of the box, including roles and
  • 00:26:47
    permissions and way more. But recently,
  • 00:26:49
    they have now also released their
  • 00:26:51
    workflows feature. So, you get a lot of
  • 00:26:53
    things out of the box, but still
  • 00:26:54
    customize many things. In any case,
  • 00:26:56
    thank you for watching and I hope to see
  • 00:26:58
    you the next one.
Etiquetas
  • 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é