So this chapter is going to be a bit smaller than our last chapter, which went on for an hour. In this chapter, our goal is to add authentication to our project. We're going to achieve that using clerk. The authentication which we develop in this chapter is not exactly going to stop here but in order to implement the things that I have planned for authentication in the future we're missing a couple of modules like our database and TRPC which is something we're going to add later. So I decided to use this chapter simply to add basic authentication which means in this chapter we have to integrate Clerk, we have to add a sign in and sign up screens, we have to add user button, right?
Which is this user button when someone is logged in, we have to add this kind of login screen, we need to add a middleware which will protect our routes, and then we can finally use that out state if you remember personal section we have this out true right so we can finally use that to show a login model if an unauthorized user clicks on that and of course we have to learn how to protect routes using the middleware. Let's start all of that by going to clerk.com. Go ahead and create an account. And once you create an account, you should be able to visit your dashboard. I'm going to go ahead and create an application.
I'm going to call it NewTube like this and you can see it says sign in to NewTube and now I'm only going to select the Google as the sign-in provider and I'm gonna leave email but you know you can choose whatever you prefer. Yeah, I would actually, yeah, I would like it to be Google. The reason I want it to be Google is because we're going to rely on users first and last name to store in our database later on. And if we just use email, I'm not sure we can extract the first and last name from that. But if we use Google, Google should automatically have the user's first and last name.
So let's just select Google sign in. Later on, you know, in your application, if you want to, you can decide to enable some more providers. But, you know, if you want to follow the tutorial exactly as I do, go ahead and just select Google. Like this. There we go.
Perfect. So now let's go ahead and let's add a clerk next. J.S. Instead of using NPM, we're going to be using Bon. Let's do Bon ad.
But before we do that, yes, I wanna be specific with my versions. So I will do the following. Let's see. I'm not sure how to check the latest version. So what I will do is just do npm clerk next JS.
And let's see what is the latest version. So it's 6.10.3. Let's go ahead and do that. Bun add at clerk slash next JS at 6.10.3. Add clerk slash next JS at 6.10.3.
There we go. That should add clerk to our project. And now you should copy the environment variables right here. So let's go ahead inside of our project. And we have to create a new file .environment.local like this and it should automatically be hidden from git so instead of your git ignore you should have .environment and then an asterisk which means basically all environment files are ignored.
And let's just add these two keys here. You should never share your keys with anyone. For the sake of this tutorial I'm using a demo account with no credit card connected or anything so I'm not at any danger of anyone stealing this but you should not share it with anyone you might forget that you added a card and someone can abuse these keys for you. So make sure you only keep them safe for yourself. So you should have the next public clerk publishable key and clerk secret key like this.
Now let's go ahead and let's add the middleware here. So update your middleware file or create one at the root of your project or inside of the source directory if you're using the source directory structure. So we are using a source So let's go inside of source and let's create middleware.ts. And let's paste this inside. If you're wondering what this regex is, you can see basically it says here.
This ensures that it doesn't match the Next.js internals and all static files. Basically, we don't want the middleware to run on loading our assets, right? But we do want it to run for API routes. And it's very cool that they added tRPC here because we will be using tRPC. In case your matcher looks different, which is possible if you're watching this into the future and their documentation has changed, I mean, I hope you use this version, Clerk Nexaria 6.10.3.
You know, you can use any version you want. I'm not telling you that you have to use 6.10.3, right? The same way I'm not telling you that you have to use the exact versions that I used for ShadCN and all these other things. But I want to ensure a certain longevity to my tutorial. So that's why I'm telling you the exact versions to install.
So if your matcher looks different, if you're watching this into the future, I don't know, a year from now, and maybe something changed, You can go ahead through documentation and try and figure if something changed on your own or you can just look at my source code and copy this from here. But more or less, this is very simple. This shouldn't be anything special. So now what we have to do is we have to add the ClerkProvider to our app. So let's go ahead and go inside of our root layout.
So instead of source app layout right here and we have to import clerk. Is it clerk provider? It is. It's clerk provider from ad clerk Next.js. Like this.
And I'm just going to wrap my entire app inside of that. Clerk provider, just like this. And let me just indent this inside. There we go, like that. And now this is what we're gonna do.
We can do Bond Run Dev so we can start seeing some changes. I don't think anything will really change yet, but let's go ahead and do the following. What I wanna do now is I wanna create my login screens. Usually, and in the past, that was thought how to do here initially, But they decided that it's simpler to just show you this part because some people don't want login screens, but I believe they still have those. There we go.
Next steps is to utilize your own pages for authentication, right? Let's click continue to the next JS guide and let's see what they have in store for us here. So build a sign in or up page. That's great. I did not know that they have...
Okay, yeah, let's go ahead and do this. So I'm gonna go ahead and do app, sign in, and then sign in page.vsx. Let's do that. Let's go and save source app folder and let's add, how did they do it? So sign in.
What we can do here is we can add them both instead of a route group called out, right? So they don't just randomly appear. So we know that they're here, but out is not gonna be a part of the URL. So we can utilize that. So sign in, right?
And then we have to create another catch all routes. So this is a dynamic type of route, which will basically catch every single variable that's passed inside anything dynamic. So this can be literally anything. And I guess that's useful for them because they might want to redirect you to somewhere after you sign in, right? So that's what they want this type of catch all route.
And then they want page.tsx inside and they want us to add the snippet inside. There we go. So now I believe that you should already be able to visit this page but let's read what they have to say. Make the sign in our up page public. By default, Clerk Middleware makes all the routes public.
This step is specifically for applications that have configured the Clerk middleware to make all routes protected. Okay, so we don't have to do this, right, because our middleware does not protect any routes at the moment. All routes are public by default. So this step is for applications that have configured the Clark Middleware to make the routes protected. We don't have to do that, right?
Because we're only gonna have a few authorized routes. You know, YouTube as an application is mostly an open app. So I think that's completely fine. Okay, so now we should be able to go to slash localhost 3000 sign in. And let's see, so sign in is not available for me.
How come? Alph sign dash in page dot dsx. Let's see, why is this page not available? It's not available because I think there's a bug here inside of how I wrote this. So I opened it through parentheses, but I only closed one.
There we go. Now it's proper syntax. So now if I refresh, there we go. We can see a nice login page here. So What we're gonna do here is we can copy this entire thing and we can call this sign up like this and we can rename this to sign up as well.
And instead of the sign up, we can import sign up. There we go, like this. And then instead of out, what we can do is we can add layout.tsx like this. And this layout can serve as a centering layout, right? So let's do this.
Let's do layout. And what we're going to do here is just add an interface, layout props. And we're going to call this children React node. Let's add layout props, children. And let's just render the children like this.
Let me just fix my typo. And now nothing should change, but you should be able to visit both sign in and sign up. So this one will say, create your account. And this one will say, sign in, welcome back, right? So the goal of this layout is to create a reusable layout, which will be able to center this.
So items center and justify center like this. Let's see. Minimum height of screen with two e's and there we go. Now it's centered. All right, this already looks better.
But we're going to be using these screens as fallbacks. So we will, most of the time, we will not show this kind of screen to the user. This will only show if the user manually tries to use the URL to go to an authorized screen. And then we're just gonna redirect them to this screen. That's what we're gonna use that for.
Let me just show you something. So this is step two, but I believe there is another step right here, which is the next public clerk sign in URL, right? So we also have to add that so Clerk knows where to redirect in case something like that happens. So let's add that exact route here. Next public Clerk sign in URL and we should also have the sign up URL.
Let me just confirm inside of environment variables that both of them exist. So, clerk sign up URL and clerk sign in URL. The reason we need next public here is because if you want to make an environment variable available to the client, you need to prefix it with next public instead of next.js. That's why they don't have it here. All right, so we've ensured that and I think that's it for the documentation.
We don't have to focus on that anymore. Great, and now I think there's also one more thing actually that I wanna add in regards to the environment variables here. So, and it's those. Clerk sign-in fallback redirect URL. The fallback URL to redirect after the user sign-ins if there is no redirect URL to the path already.
Right, so this is useful. If the user doesn't have any predefined redirect URL, we're going to create a global fallback. So it always goes to our root page. Even though it says it defaults to slash, I found that when using the clerk model, which is something that I'm gonna be doing, that doesn't happen. So we're gonna go ahead and add it either way.
So let's do next public, clerk sign in fallback URL, go to the root page and sign up fallback URL, go to the root page as well. Yeah, Okay, even though it says it defaults to here, that wasn't exactly my experience, but with one specific model, which I'm gonna show you in a moment once I add that. Okay, so we now have this ready. Great, so now we should be able to log in, but before we do that, how about we go to our localhost 3000 here, like this, and actually make this sign in or out button react to whether we are logged in or not. So we can do that by going inside of modules out UI components out button.
Let's mark this as use client component. This is very important. We need it to be use client. And now let's import user button from Clark Next JS, sign in button, signed in and signed out. So all of these things from Clark Next JS.
And now we're going to remove the to do here because we're actually going to do it. So I'm going to wrap the entire thing in a fragment like this. And then what I'm going to do is first, I'm going to add if we are signed out. If we are signed out, that's when we're going to render this, right? And then I'm going to wrap our button in a sign-in button.
Like this. There we go. So Now, let me just see, I have some errors. So that's unused files, that's fine. If I click on sign in now, it will redirect me to the sign in page, right?
So that's cool if you like it that way, that's perfectly fine. But here's a cool thing, you can direct the sign in button to use the mode model. I like this better. When you click on it, there we go. It shows up this sleek model, right?
What I've experienced is that when you use the model, this doesn't really work. So sometimes it will take you like to your account dashboard in Clerk, but if you explicitly set this routes, then it will always lead you back to the root page here. All right, so we now have that. And now let's create a state when we are signed in. So signed in, we'll use the user button component like this.
And the user button, well, doesn't really need anything, I think. Right? So let's go ahead and try it out. I'm going to click sign in, continue with Google. I'm going to use my account here.
I'm going to click continue. And now after this loads, I should be redirected and there we go. We have the user button and we can update our profile. We can remove or change our profile picture. We can connect or disconnect our accounts, all of those things.
And inside of your dashboard, you should see your first user right here. And inside of here, you can also, you know, impersonate that user, ban the user, delete the user, or simply look at their profile and change any information you have about them. So quite useful things you can find here. So now what I want to do is the following. I want to go ahead and add a little to-do here.
Add menu items for studio and user profile. So right now we don't have either of those, but Clerks makes it very easy to add multiple items to this user dropdown, even though they are going to internally redirect somewhere. So they're not going to use anything clerk related. So that's really cool. Great.
So we're going to have that. And now let's go ahead and let's Log out. So that works as well, perfect. And one thing that I actually wanna do is I wanna go inside of my layout right here and I wanna give the clerk provider an explicit after sign out URL to always go to the root page. I like to be explicit even though I think this is the default.
I like to be explicit so I know exactly that's what's happening. Great, so now what I want to do is I want to go inside of my main section for example and let's go ahead and actually do this. To do something on click, let's actually make it open the clerk model. So what we can do is we can import useClerk from clerkNext.js like this. So const clerk will be useClerk.
And we can also add user ID from useAlf. There are many hooks that you can use from clerk. For example, you have useUser and things like that. But I think useAlf is, it's very simply just loads the clerk token, right? It doesn't have to load anything.
It will wait for clerk to load, but the hook itself is not really loading anything, right? So let me just escape this. So instead of extracting user ID, you can also use isSignedIn, for example, like that. And then what you can do here is on click if we are not signed in And if this item has the out feature marked, we're going to prevent default. Let's get the event.
So prevent default on here, and let's return clerk open sign in. And then here we're going to, well, nothing actually, right? It's just going to override the link feature. So by default, is signed in. So by default, when someone clicks on the sidebar menu button, it will lead them to the URL.
But in case something this is our main section so for example subscriptions should be unclickable for a person that's not logged in. So home button works if I click on trending I get a 404 so that technically works but if I click on subscriptions there we go I get a model right let me just go ahead and try and log in and if I click on subscriptions now I get a 404 exactly what I wanted perfect So now let's go ahead and let's do the same thing inside of the personal section. So personal section right here, and we can do the same thing. So let me just add the imports here from Clark Next.js like this. Let me go ahead and copy this too, add it into the personal section, like that.
And then I can just copy the onclick. And we can remove the to-do comment here. And I think that the same thing should now work. So inside of here, there we go. Perfect.
So that works now. What I wanna do now is just learn how to protect the routes using the middleware. So right now our middleware is allowing us to use any route, right? It's not explicitly protecting anything. So how about we create a new route?
Let's go inside of home here. Let's call this protected. And I'm going to create a new file inside called page.tsx. Page, the only authorized users should see this. Or only logged in users, right?
So if I now go to localhost 3000 slash protected, even though I am logged out, I can see this page. How can we fix that? Well, very simply, If we go instead of source middleware.ts we can learn how to use it. So we're going to add create route matcher from here and define const is protected route to use the create route matcher and open an array inside and inside we can simply pass slash protected like this and then we can modify the clerk middleware to be a bit more explicit so let's get the auth and the request here and if is protected route passing the request, in that case await auth.protect. As simple as that.
So now if I refresh this, I am redirected to my sign-in page. So that's why we need the sign-in pages after all. And you can see inside of your URL, you should have the redirect URL to read you back to the protected. So if I continue with Google now, I am redirected back to the last page that I tried to access, right? So that's how that works.
And in case you're wondering, well, what if I have a whole sub route that I want to protect, right? Inside of here, I should have something, right? And if I go inside of page.tsx, Let me just copy this. See this sub route, for example. And if I go and log out, and if I go to slash protected slash sub route, is that's what we called it?
We called it something. So something. I can still see this, right? Because my middleware explicitly only protects this route. It doesn't protect slash protected slash something.
So what you can do in that case is give it a little parenthesis and then an asterisk. And now if you refresh, all routes under that route will be protected. Great. So I hope you've learned how to use Qlert now. It's super, super simple.
But there is one, let's call it a problem here. The problem is that at the moment, we are not synchronizing these users to our database. That's what we have to do next, because we're gonna need to keep track of which user uploaded which video because these videos will be displayed here. And then if I go ahead and change my profile picture, we need a way for that profile picture to update to every video card that my user uploaded. We can only do that by synchronizing our clerk users to our database and we can do that with webhooks.
So this is what we're gonna use next. Webhooks right here. We can establish webhooks and then every time a new user is created, updated or deleted, it will contact our app and it will tell the database what to do. Update that user, delete that user or create that user in the database. But before we can do that, we're gonna have to establish our schema and our database in the first place.
So I believe that's what's gonna happen in our next chapter. Great, great job. Let's just mark this as completed. There we go. Let's do that.
We integrated Clerk, we added sign-in screens, we added the user button, we added the middleware, we used the out state on the sidebar sections, and we learned how to protect middlewares. Great, great job. Thank you.