STOP using Layouts for Authentication!

แชร์
ฝัง
  • เผยแพร่เมื่อ 20 ต.ค. 2024
  • Layouts combined with Server Components are awesome, and allow us to make database calls right from out components. However, there is a common pitfall with them when it comes to how we think of their rendering order. This is critical if you are trying to hide specific content using a layout check, as you may find the content can still be exposed using a GET request. Lets se what we can do to fix that, and explain why.
    Diagrams: app.eraser.io/...
    Blog Post Explainer: www.ericburel....
    ---
    🐦 Twitter (X): jollycod.ing/x
    🤓 Personal Site: jollycod.ing/me
    💻 GitHub: jollycod.ing/git
    JollyUI: jollycod.ing/ui
    Where I Work: jollycod.ing/work

ความคิดเห็น • 84

  • @DiiiaZoTe
    @DiiiaZoTe 6 หลายเดือนก่อน +12

    Something to keep in mind is that the middleware uses the edge runtime on Vercel and not the node one. Also if your auth system uses database sessions and not JWT, you may encounter some difficulties working with the middleware... I'd recommend to simply add it to the page.tsx directly or a template.jsx if you encounter issues.

  • @hongz1
    @hongz1 6 หลายเดือนก่อน +2

    That is how you need to implement access and refresh token and place the refresh token into redis server. Let the redis record expire in certain days after automatically and also delete if requested ip is different than the first login ip.

  • @Zeryther
    @Zeryther 6 หลายเดือนก่อน +18

    Good video, but I hate using the middleware in Next.js. My main problem is that you can only have one of these per project and I've never been able to get a good implementation for chained middleware going. As someone coming to Next.js from previously using Symfony, the framework is really lacking there imo. If you want to use the Middleware for many different things like i18n as well, it gets very annoying to use very quickly.

    • @JollyCoding
      @JollyCoding  6 หลายเดือนก่อน +5

      I agree, middleware is a place NextJS could massively improve on!

  • @ashtongeorge3984
    @ashtongeorge3984 6 หลายเดือนก่อน +3

    This was really informative, I am getting into authentication with Firebase and NextJS so this was a great recommendation

    • @dincercetiner1449
      @dincercetiner1449 6 หลายเดือนก่อน +2

      Let me save you some time, Firebase won't work inside middleware because it uses node runtime, not edge runtime.

  • @davidlintin
    @davidlintin 6 หลายเดือนก่อน +16

    Please do a video on chaining middleware 👍🏻 I think it’s a natural segue from this video 💪

    • @JuicyBenji
      @JuicyBenji 6 หลายเดือนก่อน +1

      I'm kinda curious on this as well, as my implementation for that is just a very long block of if statements for each scenario since you're only allowed that one middleware file and I'm curious to see if there's a better approach for that.

    • @davidlintin
      @davidlintin 6 หลายเดือนก่อน

      ​@@JuicyBenji perhaps use an enum for the particular states and switch over them? - could be an option? - also better code readability

    • @JollyCoding
      @JollyCoding  6 หลายเดือนก่อน +1

      Will look into it!

    • @davidlintin
      @davidlintin 6 หลายเดือนก่อน

      @@JollyCoding your video on firebase-admin & ssr was fire btw.

  • @zendatastudio
    @zendatastudio หลายเดือนก่อน

    I think in most usecases securing the API will be enough, but if you absolutely need to hide everything then go for middleware.

  • @MrChabi30
    @MrChabi30 6 หลายเดือนก่อน +1

    Can you fix it with lazy loading screen the paid content? So if layout doesn’t render children, they don’t get loaded

  • @dincercetiner1449
    @dincercetiner1449 6 หลายเดือนก่อน +3

    So for the inner layout file (where the secure page is located), it's not being served if it's the FIRST time the layout is requested. From what I understand, you must be able to somehow bypass the authentication method FIRST (!isAuthenticated();) and THEN on the subsequent requests, it won't require the isAuthenticated() method to run in order to serve you the page files. Do we agree? Because layout.ts is not meant to be executed twice, but you must at least successfully execute it once.

    • @AnasSAHEL
      @AnasSAHEL 6 หลายเดือนก่อน +1

      yeah that's what I thought too

    • @JollyCoding
      @JollyCoding  6 หลายเดือนก่อน

      No I don’t believe so any react server component can be called with a get regardless of its parent components.
      Will have to double check this though, but I never bypassed the isAuth step in the video I just never even needed the layout component to run for the get request.

    • @dincercetiner1449
      @dincercetiner1449 6 หลายเดือนก่อน

      @@JollyCoding i'm not sure if you tried bypassing after the first render, because after layout.tsx is executed once, the serving order of layout.tsx and page.tsx becomes unimportant. I'd be interested to see if you analyze the initial layout.tsx request, to see if we can peek into page.tsx without executing isAuth() where the auth token from the cookies is checked. 👍

  • @kleqx2842
    @kleqx2842 6 หลายเดือนก่อน +32

    Good, but probably this will not be considered any security issue 99.999% of the time. What do you have on your dashboard that UNLOGGED users cannot see hahaha? If the page behind paywall or login render some sensible thing without proper authentication it means that you are doing ANOTHER thing wrong. Why are you sending sensible information without receiving a auth token from the client?

    • @anguswett
      @anguswett 6 หลายเดือนก่อน +6

      That’s what I was thinking. A simple API call would actually make it secure. Who cares what screen the client is on? It’s the client!

    • @JollyCoding
      @JollyCoding  6 หลายเดือนก่อน +6

      It was a pattern I had seem people use for simple things as mentioned like a paid blog post, and served as a useful learning tool to inform that layouts are not middleware, and are not guaranteed to render first.

    • @zeeeeeman
      @zeeeeeman 4 หลายเดือนก่อน

      He's talking about layouts not pages. I overlooked this too.

  • @suzma_a
    @suzma_a 5 หลายเดือนก่อน

    queeestion? can you also check in middleware for different subscription tiers? eg. there are three groups of posts (posts and info to which group they belong is fetched from cms) thanks!

  • @allefdouglas9693
    @allefdouglas9693 6 หลายเดือนก่อน +1

    I have an application where the backend (which is made in golang) set the cookie with the token (we can't change the way it works on the backend). So I can't get the user data using middleware, as it is running on the NextJS server, and the token is saved on the client side by the backend directly. There is a way I can change it to work properly with middleware? Now I using Layout to go to the backend, see if everything is ok, and if not I am redirecting the user to the login page. It is working, but i am not sure it is the right approach here.

    • @theitaliandev
      @theitaliandev 6 หลายเดือนก่อน +1

      You get the cookie from the incoming request and so call your Golang backend with the extracted cookie to get the user data in the middleware.
      export function middleware(request: NextRequest) {
      let cookie = request.cookies.get('cookie-name')

    • @sportstechgistarea9865
      @sportstechgistarea9865 6 หลายเดือนก่อน

      You might not be able to read server side cookies from the client. So I’d suggest just hit the /auth endpoint to check and redirect user if you get a 401 or 403

  • @lfades
    @lfades 6 หลายเดือนก่อน

    Even if you use middleware, it's good to still do authentication checks inside the server components. Reason is that Middleware doesn't really live in the same place as the Next.js server when it's rendering the pages (and depending on how you deploy, like in Vercel, it doesn't even live in the same runtime). So if you move authentication to Middleware only then you're creating an abstraction of something that's critical and could be dangerous. Middleware is better suited for redirects/rewrites, but proper authentication and security should be part of the data request.

    • @XxZeldaxXXxLinkxX
      @XxZeldaxXXxLinkxX 6 หลายเดือนก่อน

      You use middleware to authenticate, and you use resource specific checks to authorize

    • @urmet
      @urmet 6 หลายเดือนก่อน

      yup. authentication and authorization are different and can/should be separate. one layer verifies who you are and another decides what you can do. without needing to worry about authentication as it can trust the layer above

  • @whezboo
    @whezboo 6 หลายเดือนก่อน +1

    I use Lucia for my authentication, any thoughts on this

    • @JollyCoding
      @JollyCoding  6 หลายเดือนก่อน +1

      Really good option, I want to do a video on it!

  • @miguelemmara5046
    @miguelemmara5046 6 หลายเดือนก่อน

    is this true if you use third party lib like next auth js?

  • @throwaway-lo4zw
    @throwaway-lo4zw 6 หลายเดือนก่อน +2

    Who on earth would ever use layouts for authentication? This is why you learn web dev fundamentals instead of jumping into frameworks like Next.js

  • @bkanhu
    @bkanhu 6 หลายเดือนก่อน

    Hey Jolly, really liked the video. I've one question on implementing JWT with NextJS. So I have 2 login pages one for clients and one for staff. the client will have a magic link auth system and the staff will have an email, password-based system.
    Each user role will have different routes like app/clients/* will have everything related to clients, and app/staffs/* will have all things related to staff. So how to handle auth in this case? The backend is in NodeJS and it's setting cookies after login, but I'm unable to make it work with middleware-based auth for some reason. And I'm using Redux with redux-persist for storing user details in local storage for managing and checking roles to if a user has access to it or not. But it is not a safe approach. So what to do in this case.

    • @Darkfamiliars
      @Darkfamiliars 6 หลายเดือนก่อน +1

      I think in 99% of cases, its not the access to the page that has to be authenticated, but the data at that page.
      If that applies to your application, you should do whatever is easiest to make sure the user is authenticated, even if its not "secure".
      If it's just the data that should be authenticated, you should just send the JWT when sending requests to the backend server, where the secret data actually lives.
      I've worked in a bank and we dident consider what this video is talking about at all. The most important thing is to have secure login, strict cors rules and all that shabang, store the jwt securely in the user's browser, send the JWT with all requests to API's and only respond with data if the JWT is valid and it's authorization level is adequate.
      Unless the page structure and data living on the static page is crucial to be kept secret from non-authorized people, just keep it simple.
      In general, its better to implement security in backend than frontend, frontend is a mess.

    • @sheheerali7059
      @sheheerali7059 6 หลายเดือนก่อน

      ​@@Darkfamiliars I am think the same why should front end handle the authentication part ( I mean route based) make the api auth part stronger that's enough if the api gives 401 then return to login page else it's 403 show it's forbidden that's all
      Unnecessary headaches to frontend.

  • @albertilagan
    @albertilagan 6 หลายเดือนก่อน +1

    Have you tried db call on middleware? Last I checked you can’t. I tried pg and redis call there before and it errored which makes me believe it runs on both client and server even tho the nextjs docs says it only runs on server.

    • @alexambrinos
      @alexambrinos 6 หลายเดือนก่อน

      EDITED so i don't spread misinformation. see the next comments. Middleware as of nextjs 14 runs always on edge (subset of nodejs api's)

    • @jaspreetmaan121
      @jaspreetmaan121 6 หลายเดือนก่อน +1

      @@alexambrinos Middleware always runs on edge even if you self host

    • @albertilagan
      @albertilagan 6 หลายเดือนก่อน

      @@alexambrinos im not sure about that because last I checked default runtime is nodejs. And development on local will give you that error.

    • @albertilagan
      @albertilagan 6 หลายเดือนก่อน

      I remember this because we had to do a workaround where instead of a db call we had to do a fetch call on a defined route api. Also we’re deploying on k8s not on vercel and runtime was never set to edge. That being said maybe I’m wrong and it’s different now.

    • @JollyCoding
      @JollyCoding  6 หลายเดือนก่อน

      I think their recommended approach, as you mentioned in another comment is calling a fetch call on an API route.

  • @diwanshuji947
    @diwanshuji947 6 หลายเดือนก่อน

    I am using prisma and it does not work in edge and was not working in Middleware is there any solution for that

    • @vincentnthomas1
      @vincentnthomas1 6 หลายเดือนก่อน +1

      Yes, dont use Prisma

  • @pramodjingade6581
    @pramodjingade6581 6 หลายเดือนก่อน

    But this only is a case when using Frameworks SSG / SSR like NextJS (where the response payload is HTML content), right?
    This wouldn't be a problem in a REST API server and Client side SPA which just uses React JS (where the response payload is JSON). 🤔 ???

    • @JollyCoding
      @JollyCoding  6 หลายเดือนก่อน

      Correct, specifically only a problem for react server components and calls that don’t include a user auth

  • @Adrian_Galilea
    @Adrian_Galilea 6 หลายเดือนก่อน

    Couple of things.
    I think you meant authorization when you say authentication (like on the title)
    Lucia-auth creator(you can check his latest blog post) and many others(supposedly even vercel/nextj.js) say authz is not recommended in the middleware.
    I'd say if your implementation is generic enough and your auth method runs on the edge fine, maybe, but implementing complex conditional logic in the middleware is a mess.

  • @LaLoses
    @LaLoses 6 หลายเดือนก่อน

    Sooo, if I'm using only react static files, I'm screwed

    • @JollyCoding
      @JollyCoding  6 หลายเดือนก่อน +1

      Well you would need an API somewhere to check that a user paid for the content and then just check the user on each request. If its a fully static SPA, with no API calls then yeah, you couldnt hide content from someone if they really wanted to get it

  • @rohitkochikkatfrancis
    @rohitkochikkatfrancis 6 หลายเดือนก่อน

    That's so cool. Never thought of it that way.
    One doubt..... Can't we use service like CLERK to avoid doing all these yourself ?

    • @JollyCoding
      @JollyCoding  6 หลายเดือนก่อน

      For anything user based I would definitely use a service like clerk or NextAuth, really simplifies the process!

  • @IkraamDev
    @IkraamDev 6 หลายเดือนก่อน

    I feel like a noob coder. How did you figure this out? Why did you bother investigating this? I just code away and not worry about stuff like this, when I should lol

  • @M1a2n3o43
    @M1a2n3o43 6 หลายเดือนก่อน

    What if i use prisma for my db queries? I must use the second option then since prisma client cannot run on the middleware 😅😢☹️

    • @M1a2n3o43
      @M1a2n3o43 6 หลายเดือนก่อน +1

      Forgot to add, what if i do this uncorrect way on a page.tsx file and not on the layout file? Is it the same?

    • @JollyCoding
      @JollyCoding  6 หลายเดือนก่อน

      I believe the recommended approach then is to make an api route and use a fetch in the middleware!

    • @fedea8489
      @fedea8489 6 หลายเดือนก่อน

      ​@@JollyCoding If the auth is in page.tsx, is the same thing?

  • @snatvb
    @snatvb 6 หลายเดือนก่อน

    just you forget return where redirect, you return from layout all content. function redirect just update response headers
    i dislike middleware, because it's only one file wihout any embeded routing decomposition, why nextjs didn't add in app folder or didn't added same folder routes - i don't know, middleware in nextjs is painful place

  • @Play_Streams
    @Play_Streams 6 หลายเดือนก่อน

    This is easily solved by checking logged-in status in the paid section page template

  • @hassanad94
    @hassanad94 6 หลายเดือนก่อน

    I dont get middleware code.
    You define ispaid = false
    Than you check is !ispaid.
    Itt will be always false. And you dont use sessiontoken just.
    Pls explain it :)

    • @JollyCoding
      @JollyCoding  6 หลายเดือนก่อน +1

      It was demo code, I didn’t bother linking an auth call for the sake of the video, in practice you’d implement that function yourself!

    • @hassanad94
      @hassanad94 6 หลายเดือนก่อน

      Okay, thank you :)

  • @Sebex142
    @Sebex142 6 หลายเดือนก่อน

    If you are not using middleware, you need to check session on server every time when you calling your API. Don't do this at layout/page level.

  • @fifty6737
    @fifty6737 6 หลายเดือนก่อน +1

    next js is broken, middleware's doesn't work, the whole framework is garbage of stitched together half ideas

  • @AlekseyKovshov-n5h
    @AlekseyKovshov-n5h 6 หลายเดือนก่อน

    I'm not quite sure what the problem is. If it's that the layout for all child pages is rendered only once, then I suppose it can be fixed.
    You can use noStore to cancel page caching, or you can use the template component in next.js that everyone forgets about
    Middleware is also a good thing and I use it myself for authorisation because it's just easier than having to specify authorisation for each page or layout, but the problem is that it's only 1. Often there will be a problem with middleware related to roles and from that you will have to invent something.
    I didn't quite get the point about RSC either. I understand correctly that in RSC it can accidentally send paid content before user authorisation is successful?

    • @JollyCoding
      @JollyCoding  6 หลายเดือนก่อน

      Its specifically for React Server Components, and people using layout pages to check for a basic paid status. Complex apps wont have had the problem as they would use per user auth on each db call.
      Served as a good reminder that layouts can not act as middleware themselves.

  • @saeedd2986
    @saeedd2986 6 หลายเดือนก่อน

    well done so nice and useful

  • @harpo187bling
    @harpo187bling 6 หลายเดือนก่อน

    Jolly good video!

  • @hoffix0123
    @hoffix0123 6 หลายเดือนก่อน

    this is great, thanks

  • @the.monologue
    @the.monologue 6 หลายเดือนก่อน

    So, then if they're unauthenticated, don't return the children? Just return an empty page *and* redirect

    • @JollyCoding
      @JollyCoding  6 หลายเดือนก่อน

      You would still be able to send a GET request for the server component that displays the paid content to a paid user.

    • @the.monologue
      @the.monologue 6 หลายเดือนก่อน +1

      @@JollyCoding but that doesn't matter in practice, they won't be able to *view* the content regardless

  • @fifty-plus
    @fifty-plus 6 หลายเดือนก่อน

    People have been fucking up authn for decades. If by now you're not using a mature stack that handles proper authn/z for you without having to write it all - it's time to use a better stack. Nice one showing cookies instead of JWT too, JWT are a terrible idea for user interactive authentication.

  • @zeeeeeman
    @zeeeeeman 4 หลายเดือนก่อน

    0:37 if you just return null if `!isAuthenticated` you won't see child content - $children will be null. It's not the end of the world.

    • @JollyCoding
      @JollyCoding  4 หลายเดือนก่อน

      You would have to do that on every single child, since the layout isn’t even run if I request the child components manually via postman. The whole point of the video can essentially be boiled down to, server components can all be individually fetched, they don’t run the layout if they are.

    • @zeeeeeman
      @zeeeeeman 4 หลายเดือนก่อน

      @@JollyCoding careful on the wording. You can not request child components. You can request child pages. How can you request a component ( not a page ) via postman? That sounds like a terrible security flaw if true.
      Btw I am not criticising what you've done. It is the correct way to do it.

    • @zeeeeeman
      @zeeeeeman 4 หลายเดือนก่อน

      Ah I get it - LAYOUTS not pages. Sorry I understand now.

  • @Fan_of_Ado
    @Fan_of_Ado 6 หลายเดือนก่อน +1

    Front end frameworks are a nightmare because they abstract everything away. It's hard to know what security aspects are automagically done for you and what you have to do yourself.
    Can we please go back to plain HTML/JS and a real server (not in NodeJS)?

    • @romankoncek150
      @romankoncek150 6 หลายเดือนก่อน

      You can use whatever you want

    • @anuvette
      @anuvette 6 หลายเดือนก่อน

      Node is a real server tho

  • @tleytek
    @tleytek 6 หลายเดือนก่อน

    what a mess, return to monke and just htmx