Build an AI-Powered Fullstack Next.js App, v3

Authentication Middleware

Scott Moss

Scott Moss

Superfilter AI
Build an AI-Powered Fullstack Next.js App, v3

Check out a free preview of the full Build an AI-Powered Fullstack Next.js App, v3 course

The "Authentication Middleware" Lesson is part of the full, Build an AI-Powered Fullstack Next.js App, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Scott creates a middleware function to ensure all routes except for the home page are protected by the authentication provider. Sign-in and sign-up redirection is configured and the authentication flow is tested.


Transcript from the "Authentication Middleware" Lesson

>> And then the last thing we wanna do is just make sure we in like right now we have off ready to go. But like we're not forcing anybody to authenticate and we're not protecting any routes. So let's do that. Let's protect some routes and force people sign up.

So we will do that. So the best way to do that is there's actually a lot of ways to do it. The best way in my opinion is just to use the middleware. So if you don't know what middleware is, it's basically just a function that you can use.

It's a function that you can run on the edge in front of your deployment in Next.js that will basically protect any of the routes that you have and run some type of check. In this case, we can check to see if someone is authenticated. So it's just a function that runs before any route is navigated to.

So in order to do that we need to go to the root of our repo, make a new file call it middleware.ts. It's not a React file so this is the TS. The name has to be called middleware, and it has to be on the root of your file.

That's a convention, that is not my opinion. It has to be called middleware, and it has to be the root on your repo. All right, and then what we're gonna do, we have this really cool chart here that does some advanced stuff, we're not gonna talk about that.

What we're really gonna do is just take this authmiddleware that they have. And we're just going to export that. So let's do that. So import the off. Actually I'm just gonna type it out and it should bring it in for me. There we go. Import off middleware from clerk next js there was going to export.

The default off middleware, it's a function where you can pass in different types of configurations. I think what we wanna pass in is going to be like public routes which should be an array. There we go. These are routes that we don't want. We don't want to lock down, right?

Because if we lock down our homepage, no one can ever see our website. So in this case, we wanna make a public route for slash. So everything else is going to be protected. But that's the only route we wanna protect is that one, or that we don't wanna protect is the homepage.

So we'll do that. Then the next thing is, it's just this regex right here. I'm gonna copy this and put it in there. And basically what this is saying, so there's two ways to configure what routes you want this middleware to run. So you can prevent the middleware from running, you can prevent this because off middleware returns a function.

So we can prevent this function from running. By putting a matcher here to determine what we want this to run on or what we don't want this to run on. Or we can just skip this and we can just write some code in here ourselves and the middle will run on every single route.

But then we can write our own checks to be like if request dot URL is this, don't do anything if request dot URL is this, then do something. So many ways to do the same thing programmatically or, this way. I think it's better to do it this way because you don't have to worry about any logic inside of this function up here.

You don't have to worry about any if statements. And, cuz, like, if you're doing expensive things in this middleware, like making API calls, making database calls. You have to put that underneath your checks it just gets really sloppy so this just like this prevents dysfunctional even running unless it matches here.

>> So basically we're saying is this is just a regex that says pretty much everything the homepage and then like the API. This TRPC thing is just like some hipster version of RPC and TypeScript that people are using today. I'm sure someone's going to teach it or use it soon.

It's pretty cool, but we're not using it. Yeah, it's pretty much just matching everything. Okay, so we got all that set up. From there, we should mostly be good to go. I think the only thing that we wanna do next is probably set up some, here we go.

We mostly just wanna set up these environment variables. These environment variables are gonna tell our sign in and sign up. Where to go after they sign in and sign up, basically. So hey, I just signed a user up, where do I go? I just signed a user in, where do I route them to?

So we're gonna copy that. And I'm gonna head over to our env.local. And I'm going to paste those in there. So the reason these have a prefix of next public. Anybody know? Anybody ever used Next.js know why those have a prefix of next public? And these other ones and this one up here doesn't.

So any environment variable you put your prefix with next public is available to you on the front end. If you don't put next public, you can't access it on a front end, you can only access it on a server. So the secret key is a secret key. We don't want this on a front end, so it can't be.

But anywhere next public, you can do it on a front end. So the sign-in URL is sign-in. The sign-up URL is sign-up. After someone signs in, we want to send them to slash journal. But after someone signs up, we actually wanna send them to this new user thing, this new user route that we, made the made the second fork, we didn't make the route.

We didn't make the page yet. And we'll talk about why we need to do that in a minute. Something to do with async behavior and a race condition. These are optional too. You don't have to provide these you can just pass them props to the sign in component and a sign up component, and it should do the same thing.

But I had like a bug when I was working on this curriculum where I forgot to change this to new user. It was it was on something else. But I passed the prop into the sign up component to say, hey, go to New User after sign up, and it would never go.

And I just could not figure it out. Like I was literally in the source code of this SDK. Like why is this not working? And it was because this environment variable takes precedent over a prop, and it was something else, and I just never thought to check it.

So, I was like, well, I'm just not even gonna use the props anymore. I'm just going to use the environment variable. So, that's why these are here. So, the last thing we're gonna do before we test this out, because if someone signs up right now, it's just going to navigate them.

It's gonna break because we don't have a page for a new user. So let's just go make a page for a new user right quick. We'll say page.tsx. We won't worry about putting anything in here right now. Let's just get it to work so we could actually test our auth to see what might be broken, so we can debug if we need to.

Hopefully, we don't. Since I've spent so much time hyping up clerk, and I'll just return a div that says hi. Cool. All right, let's give it a try. You may want to stop and start again just to have those environment variables be reinitialized, although I don't think we need to.

I've just run into so many issues where I had to reset like if I were just restarted to fix some of the things. I just, every time I changed the config file the next config. Every time I change a database schema, every time I change an environment variable, I just restart cuz it just eliminates a lot of potential issues.

Now, if I go back to our app, I try to reload here. It's initializing and the expected behavior happened. We didn't get forced to a sign-up page because we said this was a public route, so that's great. But now if I try to go to slash journal, let's see what happens.

We immediately get redirected to sign in. I don't have an account, so I'm not going to sign in. Instead, at the bottom, I'm just gonna click sign up. Redirects me to the sign up page here and what you can do your email your password or whatever or just continue with Google, I'm just gonna continue with Google, gonna click that, and- Looks like it navigating me to journal, which is fine.

We'll look at that in a minute, but that's not what we wanna look at. What we wanna look at instead is if you go back to our clerk dashboard, it should have went away from getting started and it should have showed you this now. Hey, what's some confetti?

And then you can see that there is a user now that is you if you sign up, so there you are, you're signed in, you're ready to go. I expected that to navigate to new user, but for some reason it went to slash journal. Why did it do that?

Let's figure that out. So I'm just gonna look for a slash journal. In here, I don't have it anywhere other than, here. So I don't know why it, I don't know how we even knew what that was. Because I didn't tell it anywhere. So let's see if we can override this with some of the props.

So in the props here I know that there is a actually, let's just go look at the docs. I know that there is 2 things we wanna do, so there's like an after sign up URL. And then a redirect URL. So I'm just gonna set both of those to the exact same thing.

So after sign up URL, I want you to go to slash new user and then redirect URL. I also want you to go to, wait, I know why I went. I know why I went to Slides Journal. I'll show you that in a second. Slash new user, is actually really smart way did it like have an implement that yourself as a headache, so let's try that again.

I'm already signed in so I think it's just going to, if I click try to sign up again, yeah it'll just keep going to journal. So until we add the sign out functionality, what you can do to sign out is just open up your browser, go to application, go to session, storage, I'm sorry cookies.

Click on your cookies and you can just clear out all your cookies here, and it also adds a JWT in the local storage, so you can delete that too. Just delete your local storage in your cookie storage and that should effectively sign you out. So now, when I go back here.

It goes to sign up. But if you take a look at the URL you can see. The reason it tried to redirect me to journal is because it kept track of the URL that I came from, which was or it kept track of the URL that I was trying to go to.

When I click that button, I tried to go to slash turtle. So it kept track of that was like, hey, this person try to go to slash journal. So after they're done, go to slash journal. So that's what it's trying to do, which is smart because I really liked that flow from a UX perspective.

When you like, I tried to go to this page, but I'm not signed in let me sign in right click. And then I hate when it just like sent you to another page that you were not trying to go to like, that's not the page that I was trying to go to like.

I wanted to go to this page so it keeps track of the page you were intending to go to and transfer that intent. So but we we should have overwritten that by adding the redirect URL here to new user so no matter what's in the URL it should ignore that, so let's see what happens.

And no, it didn't, I think there's another prop we have to add somewhere else.

Learn Straight from the Experts Who Shape the Modern Web

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