Now let's go ahead and let's set up our database and our authentication to our project. First things first, I want to set up Convex, which is going to be our backend and database for this project. So head to convex.dev or use the link in the description and create an account. After you've successfully logged in, once you go to the dashboard, you should see a prompt similar to this. As you can see, I already have a project right here, which I've used to develop this app initially, but you're probably gonna have an empty screen and an option to create a project like this.
If you want to, you can create a project from here, but instead I'm going to go ahead and follow the documentation from Convex for Next.js Quickstart. So let's go ahead and do that. As you can see we already have our next app so we don't have to run this command. Instead we need to make sure that we are inside of our project and then run npm install convex. So let's go ahead and do that.
Make sure you are inside of your project here and I recommend that you actually shut down your localhost and then just run npm install convex like this. After convex has been installed you're gonna go ahead and run the next command which will set up convex dev deployment and that command is npx convex dev. So let's go ahead and run that. So what this command is going to do as you can see right here this will prompt you to log in with github create a project and save your production and deployment urls. It will also create a convex folder for us to write back-end api functions.
So let's go ahead and run npx convex dev. So I am already logged in So it didn't prompt me to sign in with GitHub. But if this is your first time running this command, it will give you a login link, which you can click, which will simply synchronize your new account, which you just created from Convex with your terminal here. So I'm gonna choose a new project here because I didn't create one from the UI. So new project and let's go ahead and give this project a name as you can see it already picked up the name of my repository so I'm actually gonna call it like that board video tutorial or I could have just pressed enter, but it doesn't matter.
Just give your new project a name. And there we go. Now it's creating a new project right here. And as you can see, it added some fields to our environment variables right here. And now it says convex functions are ready.
So this command npx convex dev besides being used to create and initialize a project is also used to run our backend right so this is like a separate backend which we have but the cool thing is that we can write it in a mono repo right here we don't need another repository for that. So make sure that you have this running and then open a new project here sorry a new terminal and in here do npm run dev. So you're gonna need two commands to run this project one to run your back end which is npx convex dev and one to run your front end which is npm run dev. Keep in mind that the project will work also if you don't run npx-convex-dev, but every time you add some changes to your database schema or add some new API functions you need to run this command again or you can simply leave it running in the background and that will synchronize everything with the convex which is really a great experience you're gonna see that once we start developing especially if you see my old projects where I use Prisma a lot where you know that every time I change the schema I need to do the whole migration process and db push and npx generate well here we don't have to do that it's all automatically run and it's so fast to work with.
Great so now once we've done this let's go ahead and refresh our localhost to make sure that this is still working as it should. Great! And now let's go ahead inside of our team here and there we go. You can see that I have a new project here, board video tutorial and you can see that it is completely empty. And we also have instructions on how to create our first mutation to create a task, for example.
And we're gonna spend a lot of time in this dashboard right here. So in here, we can see our data and our tables, just like in MPX Prisma Studio, for example. But the cool thing is we also have logs. So you're going to see that once we create some API routes in convex, logging errors or some info is as simple as adding console log to our API function, which Sounds like a trivial thing, but it's actually so impressive how well it works and how much it helps you debug in development and also in production later on. And not to mention that this entire thing is real-time, which will give our app an amazing optimistic feel.
Great. So now that we've set up our backend it's time to set up Qlerk and connect it with convex using a JVT template so we can actually add a login screen here. So the next thing we have to do is we have to go inside of clerk.com and go ahead and create an account or sign in. Once you're signed in go ahead and create a new application. So in here I'm going to give this application a name of Bordi.
So you can see how that's gonna look like. It's gonna say right here, continue to Boardee, and make sure that you select email address. This is very important because if you don't allow email addresses, you're not gonna be able to add invites for organizations which also come from Clerk. And besides email addresses, I also like to allow Google. So it doesn't matter what else you allow here, you can see you have a ton of options.
What matters is that you also include email address. And then go ahead and click create an application. And then inside of here, let's go ahead and let's set up our project. So let's go ahead and copy this right here and let's create our .environment.local file inside of the project. So let me go ahead and expand all of this and I'm going to create a new file dot environment dot local.
Oh, my apologies. We already have that environment dot local because convex has generated one for us. As you can see, this is my convex URL and this is my convex deployment. Great! So just below that go ahead and in your existing environment.local simply add the next public clerk publishable key and clerk secret key which you can find right here after you've successfully created your project.
And then go ahead and click continue in docs and just make sure that next.js is selected right here great so let's go ahead now and let's install this package npm install clerk next.js so for that I'm gonna go inside of my terminal here Let me just expand my screen as much as I can. And if you want to, you can shut down both terminals while you're doing this. So let's just do npm install clerk next JS here, and then let's go ahead and see what else we have to do after we've done that. So we've already added our environment keys, so we can skip step 2. And then what we have to do is we have to wrap our application inside of a clerk provider.
But the way we are going to actually do this is by creating a universal provider with both convex and clerk. So how do I know that that's how we need to do that? Well, that's because I have the convex clerk documentation right here which shows us these exact steps you know sign up to clerk create an application but then we also need to create a jvt template and then you're going to see right here that we need to create a convex provider with clerk which actually uses that clerk provider which we are seeing right here so I'm gonna skip this step for now and instead I'm gonna go immediately and create a middleware file so our app becomes protected so let's go ahead and copy this from the middleware part so step 4 require authentication to access your app and let's go ahead and create a new file here I'm gonna call it middleware.ts and remember middleware is part of reserved file names inside of Next.js. So please don't misspell this, otherwise it's not going to be registered as the middleware. And simply paste this inside.
What this is going to do is it's going to protect every single page inside of your app. So right now, if you started the app, I believe we would have gotten, we will get an error because we didn't wrap our app inside of clerk provider, but don't worry, we're going to do that in a moment. So just make sure that you have your middleware set up here. So your app is protected and that's actually it for this part of clerk. We can close this for now.
And instead what I want to do is I want to go back inside of my clerk dashboard and create a JVT template. So let's go ahead right here inside of our clerk dashboard and in the sidebar here you can find JVT templates. So go ahead and click on new template here and here we have the option for convex. So select convex and go ahead and give it a name of convex like this and in here all that matters is that aud is also named convex and you can see that right here when we have to add our out config out config for convex we're gonna have to read the aud field and that's gonna be our application ID for our configuration. So just make sure that AUD is convex right here.
Perfect. And you basically don't have to change anything here for now. Later, we're going to extend our JVT template here with some other information you can see that we can add a bunch of things so whenever we destructure our user we have some more information like the organization and stuff but for now you can just click apply changes and make sure that you have this convex right here. So it's not automatically created once you click new template. You need to click apply changes and then you're going to have convex template generated right here.
Great. So now let's go ahead and see what it says. It says copy the issue URL from the issue input field but before we do that let's actually copy this from convex out config.js and you can see where that is in the convex docs authentication clerk right here I'm also gonna leave the link in the description but it's also a very short piece of code so you can just code along with me. So let's create inside the convex folder a new file out.config.js. Let's go ahead and quickly do that before we wrap our application in the provider.
So inside of convex let's create a new file out.config.js and inside I'm simply going to paste this right here and you can ignore the warnings here. And what we have to do now is we have to change the domain to be our actual issuer and the application ID can stay the same. Well, you will know whether it can stay the same or not. So the application ID needs to match the AUD claims field. So go back inside of your JVT templates here, inside of your newly generated convex, and confirm that the AUD is convex.
Great! And then in here you have the issuer field, so just copy the issuer like that, and replace this dummy string where it should hold the domain with your account like this. Perfect. And now that we've done this, to ensure that this auth.config.js is correct and that you don't have any typos or misspellings here what you can do is go inside of your terminal and you can attempt to run npx convex dev and if it is successful it will just tell you that functions are ready there we go, convex functions are ready but I believe that if you try and add something that doesn't exist like this there we go you can see how that will throw you an error because you have an invalid auth.config.js so just make sure that this is application ID and that this is a domain and there we go if everything is okay you're just gonna see convex functions are ready perfect so I'm gonna shut this down for now And now let's go ahead and let's create our provider, which we can find right here. I believe it is in step 5.
Sorry, step 8 right here. So configure convex provider with clerk, but ours is going to be a little bit different. So we're going to use a mix and match of the instructions from the documentation from clerk.js and the one right here. But we actually don't need documentation for that. You can just follow along exactly what I'm doing.
So let's go ahead and create a new folder in the root of our application called providers. And then inside, let's go ahead and create a new file convex-client-provider.dsx. Let's go ahead and mark this as use client and let's go ahead and import the clerk provider and let's import use out from at clerk slash next JS now let's go ahead and import convex provider with clerk from convex slash react clerk like that and now let's go ahead and let's import the following from convex slash react that's gonna be out loading authenticated and we're also gonna have convex react client Like that. And now let's create an interface convex client provider props, which is going to have the children, which are a type of react.reactNode. So this is going to be a wrapper around our entire application.
So it kind of works as a layout, right? But it's not exactly a layout. This is just a provider, which will protect all of our children, which will be all of our app with authentication. So now let's go ahead and let's get the convex url to be process.environment.next public convex url and you can put an exclamation point at the end here like that so it's never undefined. Great and you can just confirm this by going inside of your .environment.local and confirm that you didn't misspell it so next underscore public underscore convex underscore url like this.
Great And now let's add a convex instance. So that's going to be new convex react client and pass in the convex URL like that. And if you don't put the exclamation point, you can see that then we have a little error here. So you can just simply put an exclamation point here because we know that we have this inside of our environment local great and now let's export const convex client provider convex client provider like that and in here what we're gonna do is we're not going to destructure the children And let's also assign the types of convex client provider props here like that. And then we're going to return a clerk provider at the top, then inside convex provider with clerk, and to it, we're gonna pass use out to be use out, and we're gonna pass in the client to be convex.
And what we have to do inside is simply render the children for now like this. There we go so you can see that we don't have outloading and authenticated being used but we're going to use that in a moment. What I want to confirm now is that once I add this to my root layout page my app will become protected with authentication and once I start my localhost 3000 I should be immediately redirected to a common login page from Clerk. So let's go ahead and do the following. I'm going to go ahead and run npx convex dev in one part of my terminal and in another I'm going to run npm run dev.
And now let's just go ahead and go inside of our app folder layout.tsx right here and let's go ahead and wrap everything inside of body with our new provider so in here let's add convex client provider and let's wrap the children inside of it and let me just show you where I imported this so right here import convex client provider from at slash providers convex client provider so that's because it's located right here in the providers folder which is in the root of my application not inside of the app folder like that great and once I save this and if I go ahead and visit localhost 3000 now I should be redirected to there we go my issue URL you can see how my URL changed because we're using a JVT template so we can use our issue URL because we've used it right here in the convex out config right here so we successfully set up our authentication with Clerk and Convex at the same time. So now let's go ahead and let's log in and see what happens. So now once I'm logged in, you can see that I'm redirected back to localhost and there we go.
Now I have full access to my application. Great. So what I want to do now is I want to add a little loading state because there needs to be a kind of a synchronization between Convex and Clerk to decide whether you are actually logged in or not. And we also need to add a way to log out, right? So let's go ahead and do that.
So in order to create a nice little loading screen before Convex and Clerk decide whether you are logged in or not, we need to find a logo for our application. So you can use any image you want. I highly recommend that you visit logoipson.com. They have amazing placeholder logos. Just make sure you don't use it for your actual business.
So they are completely free and open source. I'm not sure if they're open source, but you can use them for your demo apps, right? So I have one downloaded inside of my GitHub repository. So you can just use the link in the description and find my public folder. And in here, you're gonna find logo.svg.
So this is straight from logo.ipsum. You can visit that website to find even more logos. So just download this picture or find any other logo you want to use for your application and go inside of the public folder and simply drag and drop that inside. So if you remember from our first module you learned that public is the folder where we're going to keep our static assets. So logo is the perfect place to put that folder in.
Just make sure you rename it to logo.svg. Make sure it doesn't have any numbers besides that. Great, so what we're gonna do now is we're gonna create our loading component, right? So let's go ahead inside of our components folder here and in here I'm gonna create a new folder called out simply to separate that from any other loading component which we might have. And then inside create a loading.dsx.
And let's import the image component from next slash image. And then let's go ahead and export const loading. And let's go ahead and return a div with a class name of full width, full height, flex, flex, col, gap, y, or justify center and items center. So it's gonna be a element which has full width, full height and uses flex to simply center our image. And we actually don't need a gap y4 at all because it's just going to be a single image inside.
So let's render this image in a self-closing tag. Let's give it the source of slash logo.svg. Let's give it an out of logo. And let's go ahead and give it a width of 120. Let's give it a height of 120, and let's give it a class name of animate pulse and duration 700.
So it has kind of an indication that it is loading. So just confirm that this logo.svg matches what you've put in your public folder here logo.svg and then let's go ahead inside of our providers convex client provider and now we can use outloading and render that instead of the children here. So let's go ahead and render the children only if we are authenticated like this. And then below that if we are outloading then render the loading from components outloading. So make sure you have outloading and authenticated imported from convex react and make sure that you imported loading from add slash components outloading which is the component we have just created.
So let's see if we need to modify anything. I want to zoom out just a bit to see if my logo is centered or not. So it seems like my logo is not exactly in the center. So every time you refresh, you should be seeing this loading component here. If you are of course logged out, it will redirect you to the login page for the issuer, right?
But we currently don't have a logout button, so it's kind of weird. We don't even know whether we're logged in or not, but we're going to fix that in a second. So we need to do something to actually center this, and I think I know exactly what the culprit is. So in here, we use the full height and full width but I believe that inside of our app folder global's not CSS you're missing some base styles here to actually allow our app to use full height of our screen so going to the app folder global's not CSS here and add HTML comma body and comma colon roots and add a height of a hundred percent like that and simply save that file and now when I refresh there we go you can see how every time I refresh there is kind of a loading screen for our app and I think that it just looks really nice especially with this pulsing effect right here. Perfect and this is of course only going to be when the user initially visits our website it's not going to be on every route change right So it's only when you first time loaded the website like this on a refresh.
Great. And now what I want to do is I want to go inside of the app folder page.psx right here. Let's change this into a div saying this is a screen for authenticated users only. And then in here, I'm simply gonna make this one below another. So I'm gonna use flex call gap wide four.
So it really doesn't matter, right? We're gonna remove this either way. I just wanna kind of make a nice screen here. In here, we're gonna add a user button from ClerkNext.js. Like that.
And we can remove this button now and there we go. It says this is a screen for authenticated users only. And if I click here I can see more information about my account. And I can also sign out completely. There we go.
And if I go back to localhost 3000 manually, I'm redirected back here. So now I'm gonna log in again. And there we go, I'm redirected back. You saw the little loading indicator and I can now see my other account. And in here, you can also see that you have the entire settings page where you can change your email, you can connect another account, you can log out from active devices, you can delete your account.
And here's a cool thing about Clerk. So if you go to clerk.com, you're gonna find a bunch of customization options right here. For example, branding, you can actually add any logo you want. So right now, when I log out, my screen just says, you know, log in to continue to Bordi, which is my application name, but you can also add a logo. So I'm going to add our logo here.
It needs to be smaller than, okay. Basically you can try and add a logo. I picked the wrong image now. And then it's that logo is actually going to appear, on the login page. And here's a cool thing.
Even though this is for pro users only, while you're in development, you can test out any pro feature. There we go. So it just says this is a premium feature and they are free to enable on development instances. So you can just click close here and now you can see how in here it says secured by Clark but if you're wondering how it looks like once you go pro you can try it out and there we go you can see how now you have no clerk branding if that's something you're interested in so I really like when companies do that when they show us the pro features without us actually needing to purchase the pro features so we can decide whether it's worth it or not. Great, so we wrapped up authentication.
We now have our app protected. We have a nice little authentication loading. And most importantly, what we achieved here is we connected our convex, which is a real-time database, which has, you know, some custom API typings, which you're going to see in a moment. And we've completely secured convex backend and our next JS application at the same time. So that's why we needed to do the whole JWT template and the issuer and all of those things.
But all of that is gonna become more clearer once we start actually building some queries inside of convex and you're gonna see how we are gonna have access to our currently logged in user using the identity there. Great, great job!