Lesson Description

The "Protecting Routes" Lesson is part of the full, Build a Fullstack Next.js App, v4 course featured in this preview video. Here's what you'd learn in this lesson:

Brian discusses protecting routes based on user authentication and the difference between authentication and authorization. He also demonstrates how to implement route protection using StackAuth on both the client and server sides, ensuring that only logged-in users can access certain pages.

Preview

Transcript from the "Protecting Routes" Lesson

[00:00:00]
>> Brian Holt: So now we have an auth system. We have a user being logged in. It's all done by cookies, just like you would expect. You could open your dev tools here. Let me just make this significantly bigger so you can see what I'm talking about. And if we go into storage and we look at cookies, right, you can see this is all the Stack stuff coming in, right? So we have a user is now cookied with and logged in via that way.

[00:00:35]
We want to now go protect something, right? So for example, if I come in here to wiki one, right now it says edit article on every single page, but I shouldn't be able to edit any article that's not mine, right? I should only be able to edit my articles. I shouldn't be able to edit your articles. So how would we do that? Well, we're going to use Stack Auth to do that. We're going to say, only show the edit article to people that have it, that have the ability to edit something.

[00:01:07]
And if someone tries to go to a route to try and edit a page that's not theirs, then we want to redirect them to somewhere else because they shouldn't be there, right? We're trying to protect them. So at the moment, because we don't have the database set up, right, because these aren't actually real articles in the database yet, we're just going to be checking for logged in and logged out. We'll come back later and do the authorization part of this.

[00:01:33]
But right now we're just going to check the authentication. And I recognize those words are very similar. Authentication is just like who you are, or it's just like you're logged in or you're not logged in. An authorization is like, we know who you are, but are you allowed to be here, right? So we're going to worry about the authorization later. We're just going to worry about the authentication right now.

[00:01:57]
So there are three ways to protect a route. I'm going to say generally speaking with Next, but specifically with Next Auth and Stack Auth. You can do it at the client side, which is usually more for convenience. It's not very safe, right? It's more just for like user experience of like, oh, you're not supposed to be here, let me get you to where you're supposed to be. There's with the server, which is really like, I'm not going to allow you to do this, right?

[00:02:22]
So that's actually where the security is, is on the server side. Or if you want to like protect like, let's say you have like an admin part, you could just say like, everything in the admin directory and inside of it, you would do that with a middleware, of saying like, check to see if this is an admin route. If it is an admin route, then redirect them out of that. That would be with a middleware.

[00:02:43]
I don't, we're not going to do a middleware today because I didn't have a good use case for it, but it's a middleware, right? Like I imagine most of you have probably seen a middleware before. It's just like a function that runs to say like, is this true, then do this. But we're going to use both client side and server side today. So let's go back to our app. Yeah, let me, I guess, bring up my notes here because it's probably helpful to see that.

[00:03:16]
We are in protecting routes. So client side redirect will look like this. It's usually use user or redirect. This tells the next, like if there's no user here. Yeah, it'd be like what we just wrote, which is here. So we say use user and you can also say or redirect. You don't want to do this on the nav page because, but I'm just kind of showing you the example. This would say like, if I can't find the user, redirect them home.

[00:03:51]
You can also tell where to redirect, but that's what this would do. But we don't want to do that. We don't want to say like get a null user because otherwise, like this is on every page, it would redirect, always redirect you home and then you get an infinite redirect loop. So don't do that. So, yeah, actually, this wouldn't actually be a client side one. This would be a server side one because this Stack server app is running on the server.

[00:04:27]
Cool. Yeah, and then I have it here in my docs of what a middleware actually looks like if you want to use something like that, which is this. So you would just put this into your app to say like, hey, if you're in this particular route, run this middleware and with that middleware, just say like, hey, if they're not supposed to be here, redirect them to the sign in page. Yeah, so you would put this matcher.

[00:05:05]
That would protect like everything in the sub path here. Does that make sense? Cool. So let's go use it for our page. Let's go put it into the edit page. So the source app wiki edit ID page. So we're going to go into wiki ID edit page, this one. So right now you can see this is all just mock data, which is fine. So at the top here, we're going to say import Stack server app and then here, it's already async, which is great.

[00:06:15]
I'm going to say await Stack server app dot get user or redirect. So again, just to emphasize, this only is going to block someone from being logged in or logged out. This isn't going to block it on who is logged in or logged out, which is what Authz will do and we'll do that momentarily. I don't know why that's boring as well. Okay, so refresh the page, ignore the error for the moment. It's letting me stay on this page, right?

[00:06:45]
Because I am logged in, but if I come in here and I say sign out and I go to wiki slash edit slash one, it's going to redirect me to the login page. We've now successfully protected that route. Because this is happening on the server, you can tell by looking at Stack server as opposed to just to see you, if it looks like this where it says use user, it's a hook so that inherently happens on the client, right?

[00:07:15]
This is not secure. This is helpful for like UX experiences, but this doesn't protect anything. Why? Because this code will never get shipped to the client, right? It's all happening on the server side. This bundle will never actually make it to the end user page. This use user, this will include all of your code and get sent down to the user. Now, the code won't be executable, it won't, it's not like necessarily the security vulnerability in the sense of like, someone's going to come in here and impersonate a user, but they can get to the code bundle and see what you're doing inside of that page, right?

[00:07:50]
So if you have like admins that have like secret keys or have secret endpoints they use, if it looks like this, this means like all of that bundle is going to get sent down and someone could like decompile it and figure out what you're doing and see all the URLs that are going out of it. Whereas this is a server component, that code will never get sent down, you can be guaranteed that that's never going to be shared.

[00:08:14]
Stack Auth is still going to make sure that the users are able to interact with those endpoints, right? So from that perspective, like, it's no less secure than just having a public endpoint. But the bundle still won't get sent down. Yeah, Mark. Why are there two lines, get user and use user? I was just showing you the difference between the two. You don't want this line because you just need one or the other.

[00:08:49]
This is how you do it on the client. This is how you do it on the server. Where is the redirect target location specified? I think it's in here. Yeah, you know, I'd have to look at the docs. I don't know what it is off the top of my head. Usually you just want to redirect them to the sign in page, right? But there are, I guess such occasions where you'd want to redirect them home. Maybe it'll tell you here.

[00:09:29]
I think it's an enumerated type. Yeah, 00, there you go. Redirect, throw return anonymous. So it looks like those are your three options. Cool. Other questions? There's kind of a meta discussion in the chat around using something like Stack Auth that has all this magic built in versus really understanding auth from the ground up. And at least I would say Scott Moss has a good API design and Node course, which you build authentication from scratch.

[00:10:02]
And there's other courses that have that, so if you want to dig in, you can. But yeah, I don't know what's your thoughts. I like foisting the complexity of auth onto security professionals, generally speaking, I like foisting the complexity onto other people just generally speaking, but in this particular case, auth is non-trivial. So you should understand auth, and I think it's good to like build some like roll some auth from your like understand like, why is it time sensitive, why do we, you know, have these various different kind of handshakes, what does OAuth do for you, some of these kind of different things.

[00:10:38]
But for something like this where the requirements of this are very normal. We're not doing anything crazy with auth here. I like using something like Clerk, Stack Auth or something like that. It's like, because I get so much for free, right? I don't want to build user management. I don't want to build emailing the user to let them know that like, you know, their reset password or something like that.

[00:11:03]
I prefer using something like Stack Auth or Clerk in those cases. Don't get me wrong, they get expensive at scale, but like, kind of what I tell a lot of startups is like, if you've gotten to the point where it's now expensive because you're scaling, congratulations, you have earned scaling problems, right? And then hire a bunch of people to go like roll your own Keycloak or something like that. I don't know.

[00:11:32]
But I like using auth services. There's a group of people that will tell you like never roll your own auth, and I don't think that's quite realistic. Because there's just occasions where it's very helpful, like Neon rolled its own auth. I don't know if we necessarily had to. But it has been helpful in some cases, right? So as always with these kind of questions, the answer is it depends, right? It's a spectrum of like, I'm okay letting some black magic in and foisting this complexity into somebody else, because I'm getting so much back and I actually don't really care what's going on in the black magic.

[00:12:06]
But there are occasions when I like, I need deep access to like what how the auth is happening, so. Most projects these days, I start with an auth service. I like BetterAuth as well. Like I use BetterAuth quite a bit, which is like the new Passport, right? It's the like, I want to run it on my servers, but don't get me wrong, BetterAuth is still doing most of the same things for you. It's just executing on your server as opposed to Stack Auth's.

[00:12:43]
So my biggest complaint would have been that I couldn't see the user's table in my database, but with this I can, so that kind of gets me the best of both worlds. Cool. Other questions? It's a good question. It's definitely one you should have an opinion on, like there's no right opinion here. So let's go to new as well, here, new page. This one's really easy, it's basically the same thing, but you can't author a new page unless you are signed in.

[00:13:39]
So Stack Auth. Uh, stuff, it's not stack up the Stack server app, the lowercase one. And we're going to import or await Stack, get user or redirect. And I think this needs to be async as well. Export. So we don't even really care about who the user is, we just care that the user is logged in at all, right? This is what, like we don't need to modify this later because we're letting any user create articles, right?

[00:14:30]
So we're just saying like make sure they're logged in. If they are not logged in, please redirect them to the sign in page. Questions here? Since we're repeating the get user, could it be done in a higher level component? Oh man, I mean. Yeah, I guess like what that would look like. I hate this. But it's a very valid point. This person is living in like 2019. Like you could do like, logged in, right, like this.

[00:14:57]
And then the logged in component would basically run just this. And then like it would redirect someone out of here, you could definitely do that. If you like this. I don't know what to tell you. I really don't like this pattern, and I'm very happy we've moved beyond the era of like 30 like higher order components. Uh, I hopefully I'm not making fun of this person. Like it's a very valid point and like this actually is not that bad.

[00:15:27]
But I remember when there was like 30 layers of this. Oops. And it looks something like you would go to a component and it would look like this, and you'd be like, okay, which one of these interacts in this different way? I, it, I'm just getting flashbacks. That's why I was like I had such a visceral reaction to that. Like if you go look at Complete Intro to React, it's going to be like V4 or V5 or something like that.

[00:00:00]
There's a ton of these nested because at that time it was very in vogue to have a lot of these. Then we got like, now everything's a hook that has its own set of problems, don't get me wrong, but it's better than this, right? Thank you for the very valid question. I hope I wasn't too cheeky about it. But you, that design pattern would work here.

Learn Straight from the Experts Who Shape the Modern Web

  • 250+
    In-depth Courses
  • Industry Leading Experts
  • 24
    Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now