In this chapter we're gonna go ahead and create our authentication setup. We're gonna be doing that using BetterAuth. We're going to configure the new auth schema, we're going to push those changes to NEON database, and we will create a very basic temporary UI which will allow us to create a new user and we will finally create, review and merge the pull request for this chapter. Let's start by adding BetterAuth So you can head to better-auth.com or use the link in the description to let them know you came from this video. So we're gonna go ahead and click get started right here.
And if you want to read more about BetterAuth you can read here. It's an absolutely amazing library. I have not seen a library as good as this in a while. So I'm gonna go inside of the installation tab here and we're gonna do npm install BetterAuth. And just for this project's longevity sake I will use an exact version 1.2.8 like this and let's see I forgot to add a dash dash legacy peer depth so of course we get an error so let's repeat this but let's add dash dash legacy peer depths and let me confirm that this was the correct version 1.2.8 it is there we go so when I add dash dash legacy peer depth so we have no error whatsoever great now let's go ahead and let's add the better out secret environment variable here so I'm going to add this And you can add whatever you want inside, or you can use the button generate secret here and just copy whatever is here.
It really doesn't matter, but it must not be empty. You need to write something inside. For production, obviously, it would be a good idea that it's something the length of this rather than just secret. But for development, it doesn't matter. Just make sure it's not empty.
Let's also set the BetterAuth URL here. And we can set it to be localhost 3000 under the HTTP protocol. So it's important that you know the protocol of your app and you can find it every time you do npm run dev. In here you can see my protocol is HTTP localhost 3000 so you can copy this and add it here. It needs to match.
Great. And now let's go ahead and let's create a better ALF instance. So the place I'm going to do this is inside of source and inside of lib I will create alph.es and I will simply import betteralph from betteralph and I will export const alph here. And let's quickly just visit my package.json just so you can double check my versions. 1.2.8.
There we go. Now let's go ahead and configure a database. As you can see, it immediately offers Postgres here, but we will actually be using Drizzle. So it has an option for that as well. Of course it does.
So I'm going to add the Drizzle adapter here from BetterAuthAdapters.Drizzle. And I will import database from at slash database which is our drizzle instance so this is the exact location that my database is in database index now that we have both of them we can add the database option here and we can select the provider to be pg which stands for postgres of course since we are using postgres this is the correct option Let's see what else we have to do. Now, we have to create the database tables. So BetterAuth includes a CLI tool to help manage schema required by the library. So you have two options to create the actual schema for your authentication.
If you want to, you can use npx better out CLI generate or you can manually create it by going inside of the database section here and you will see every single database item that we have. What we are going to do is we are going to use the CLI here. So we are just going to use the generate one. We are not going to use the migrate one because we will be pushing directly to the database. Now for longevity sake, I'm also going to show you the version at the time.
It looks like the version of BetterOut CLI needs to match the BetterOut. I'm not sure if this is a coincidence but it makes sense that these two match. So yes the version I'm using is 1.2.8 and we don't need a dash dash legacy peer depths here because we're not installing anything we're just generating. So let's click generate and let's see what happens. I have to install this package first 1.2.8 and let's see what will happen once this completes.
So it's asking me do you want to generate the schema to ./.altschema.ts? I'm going to select yes. I want it to be in a separate file so it doesn't accidentally overwrite whatever I have in my schema. So I will press yes. And there we go.
Schema was generated successfully. So now, what we're going to do is we're going to go inside of the out schema here. We can remove the integer. We don't need it. And now, what I want to do is I want to copy things just one by one from our schema to my source database schema.
So instead of this users, you know, we will have an actual user here. So we can remove this actually. And We can also add this here. There we go. And what I would like to do is just fix the indentation of these so it looks a little bit better.
There we go. Like that. After we defined our user, let's add our session. So the reason I'm doing it one by one is just so we are a little bit more aware of what we are adding to our schema. And I'm just formatting it a little bit.
So what do we have so far? We have the user here and we have a session. And you can see that session has a relation to the user. And once the user is deleted, the session will be deleted as well thanks to the cascade method here. We also know that the email has to be unique, for example.
So that's why we are going one by one, just so we're a tiny bit more aware of what's going on here. Now let's copy the account one. So the accounts will be used for social logins here. Let me go ahead and fix the indentation on this one here. And this one is pretty simple.
So it has a relation to user as well. And let's add the verification, which looks like to be the last one here. And verification is self-explanatory. If we want to add verification, we have the table for that as well. There we go.
So one, two, three, four tables is looks like we've added here. So let me just confirm here. One, two, three, four. We did not miss any. So we can now go ahead and remove the out-schema.
We no longer need that here because we have added it to our schema right here. And it looks just fine. Let's see what else do we have to do now. So the next step here is to migrate, but we are not doing migrations, we don't have to do that we have our script for synchronizing with the database. And that's going to be database push, it's much simpler this way.
So it looks like we can do that already. So let's do it. Let's see if we will encounter any errors or will this work by itself. So I'm going to try and do npm run database push, I think we might actually encounter some errors here. So actually no errors, but we do have a question is accounts table created or renamed.
So this is asking us a question because we previously had the users table, which we deleted, right? So we have two options here. If you want to, you can just nuke the database from Neon and just create a new project with the new database and have a clean slate, right? But what you can also do is just answer to these questions. So I'm going to try answering the questions.
If it seems to be okay, no problem. But if you, for whatever reason, think you've messed this up, you can always just create a new database and just obtain a new database URL, paste the new database URL, run the command again, and you won't have these questions. So the account table is a new table so using the arrow keys I will select the plus option and press ENTER same for the session the only thing I will say is the user so the users have actually been renamed here and the verification has been added Now in here is email verified column created or renamed. So this is a create created column. Image is the created column created that is created updated at is created.
And looks like at the end of all of that, I got some errors. So I'm not exactly sure if this worked correctly. So that's why I wanted to tell you, you don't have to worry, even if you mess this up, like I did, what you can do very simply is go inside of your settings here, just delete the project. So you have to learn how to work with your database. Of course, obviously, this is just for early development phases, you would not consider actually doing this in production, you would have proper migration status, right?
But let's just try again, meet AI2, for example. And let's click Create. And again, let's click Connect and copy the snippet. And in here, Let's just paste this here. So just make sure you have the new database URL and you don't have to change anything else.
Let's do npm run push now. And let's see if we will have any errors, no errors at all, because this is a completely clean database. And if you go inside of your tables here now in MeetAI2, you have account, session, user, and verification, those four tables which we just added. So even though we could probably work our way around this issue and resolve it. I just want you to see how I actually do these kinds of things.
When I develop things, I often get into these kinds of conflicts. Since I'm in early development phases, I can just nuke my database and speed up the process. Again, please only do this in early development phases like this one, where we are just learning how all of this works. Excellent. So we have done the following.
We have configured the out schema and we have pushed the changes. I'm not sure if we can mark this as completely integrated. I'm going to check this one last. Let's see what else we have to do. So we now have to add some authentication methods.
We're going to add social providers later. The first one we're going to do is the normal email and password. So let's go inside of the auth here and let's say email and password enabled true and just like that we have enabled normal email and password but besides that you have passkey, username, magic link, you have so many different ways of authenticating here. And that's only what they provide you with. There's also the community plugins.
So it's absolutely insane. Now what we have to do is we have to go inside of app folder API out. So let's quickly go ahead and do that. Source app folder, let's create a new one called API. And inside inside of square brackets out.
So we are following instructions exactly as they say, which I've messed up, my apologies, out without square brackets. And then inside of square brackets, three dots, all. So this is kind of a catch all route. And then finally inside of that, a reserved file name in Next.js, route.ts, which represents an API. So we can then copy this and paste it inside.
So we are registering our auth client here to post and get route for our localhost 3000 slash API slash out and then whatever comes after it this is like a catch-all universal route excellent so now that we have that we also have to create the client instance. So let's go inside of our lib here. The same way we created out, we will now do out dash client dot ts like this. And we can just copy this entire thing here and paste it. So the base URL of the server, you can see it says optional if you're using the same domain.
So you actually don't need this at all. Because we are on the same domain. And finally, you now have... You can now... My apologies.
No, I thought that this was an example, but they are showing you that you can also export individual methods and hooks from create auth client instead of exporting the entire auth client. But I'm fine with this way. And there we go. So that's it. You are now ready to use BetterAuth in your application.
Continue to basic usage to learn how to use the ALF instance to sign in users. So let's go inside of the basic usage here and what we're going to do is inside of page.tsx here We will just create a very simple form here. So I'm going to mark this as use client so I can make it reactive and add some hooks here. And I'm going to add email, set email, use date, and then I will do the same thing for name, set name, and password, set password. Obviously, this is not how we will build forms, but what we are doing now is just a very, very basic confirmation that our BetterOut has been integrated properly.
So what I'm going to do here is just a div, and then I'm going to add an input from components UI input, which we have because we added all components from chat CNUI. I'm going to give this a placeholder of name, this one will be email, this one will be password with a type of password. And I will just go ahead and give this one a value of name and on change event target value. And I will just copy these and add them down here. There we go.
Oops, I completely forgot to actually wrap this. So this will be set name. This will be set email. This will be set password. The value here will be email and the value here will be password.
I will just collapse this so you can see better. Okay, I just collapsed these elements so you can see them better. And let's go ahead and try it out. All we need is a button here, which will say, Create User. So I'm going to do npm run dev, and I will visit my localhost 3000 which should now show my very simple form here.
We can give this a class name padding for flex flex column and gap while for just so they have a little bit more space here. And what I will focus on here is my network tab. I want to see what's going on here as well. So what we want to do now is we want to learn how to use BetterAuth here. So let's import AuthClient in here.
And let's use the OutClient in our onSubmit method here. So what I'm going to do is call out client.signin. Now let's see, is that the correct one? My apologies, it is signup.email. And inside of here, I have to pass in the email, I have to pass in the name, and I have to pass in the email, I have to pass in the name, and I have to pass in the password.
So these are the three required ones. You can also pass the image if you want to and the callback URL. And let's also add these right here. So onError, let's do windowAlert something went wrong. OnSuccess, windowAlert, success.
Just so we are aware of what's going on. Great. So now that we have this, let's go ahead and try submitting. So const on click on submit. So I think by default, we should get an error here just by clicking this.
Let me try. There we go. Something went wrong. Obviously, we get an error because we have an invalid email because the email was not passed at all so I'm going to set my name to be Antonio my email to be Antonio at demo.com and let's use the password to be password one hint your password needs to be I think at least eight characters, otherwise it will throw an error. So if I just do 1, 2, 3 and click create user, again, we have an error here, password is too short.
So try 1, 2, 3, 4, 5, 6, 7, 8. And let's see. Again, something went wrong let's see what exactly it is there we go so this one wasn't exactly clear from the return here from the network tab but if you go inside of your terminal you will see some errors. Server error, weather out error, drizzle adapter, the model user was not found in the schema object. Please pass the schema directly to the adapter options.
So this is what I was waiting for because I knew that my auth configuration looked a little bit different so I was waiting for the reason why and it looks like because we need to add our entire schema. So let's import asterix as schema here from at database schema. And let's go ahead and pass the schema here and simply spread the schema. Like that. So we have now connected our schema, user, session, all of these things with the schema here.
And I think that if you kind of like try and rename something here, You might actually get an error here or not, maybe not. But let's try again now. So I'm going to try Antonio, AntonioDemo.com and 1, 2, 3, 4, 5, 6, 7, 8, create user, looking promising, and there we go. Success, 200. And we can now go inside of our Neon console here, refresh this and go inside of user.
And there we go, you can see the actual user. So Antonio Antonio demo.com. You can see when we are created you can see the matching account with the credential provider id because we didn't use the social login we used credentials and you can also see the active session because we are automatically logged in actually. And the verification doesn't exist because we didn't add anything regarding verification. But yes, this is the part that was missing, adding our schema here.
And one more thing I want to check here is, is there a nice way to maybe display that we are logged in? Let's say, can I check? Let's actually try and follow the documentation here. So this is sign in. Okay, that works just fine.
Social sign on, how do I actually see the session? That's what I'm using. There we go. The session. So I'm just going to go ahead and add this here from out client dot use session.
All that I care about is the data which remaps to session here. So what I'm gonna do is I'm gonna check if I have a session, we're going to return a div here with a class name flex flex column padding for in gap y of four and I will add a paragraph logged in as session dot user dot name like this. And let's add a button here, sign out, on click. And I think we can just do out client sign out here. Like this.
There we go. You can see that initially it shows the register. That's because this is an actual fetch request. So it's loading for some time. You can of course extract is pending here if you want to handle that but this is just for demo and when I click sign out there we go and the cool thing now is that if I try registering again I will get thrown an error because this email is already taken.
User already exists. Perfect. So the only thing that's missing here is a way to log in. So let's quickly add this as well. Just for fun, let's do it.
Let's do a class name here. Flex flex call gap y 10. And we can just copy this entire thing and paste it below. And this will be login. This just needs the name.
And on submit will be on login here. And let's just copy on submit here. Let's call it on login. Out client sign in. Looks like we can also use dot email just like that.
There we go. So let's try this. Let's try Antonio demo dot com. And yes both of them will be filled but that's completely fine. Let's try the wrong password first.
Password. Click login. Something went wrong and I didn't open my network tab but I'm pretty confident that we got, as you can see from the code 401. Let's try again. Invalid email or password.
Now let's try actual password here. Actually, one, two, three, four, five, six, seven, eight. Let's try logging in. And success. There we go.
Logged in as Antonio. Just like that, we have implemented Credential Auth. And it only gets easier from here. This was the hardest part of our authentication. Absolutely amazing, amazing library.
And of course, we only tested this in the client mode because it's just, you know, easier to create a form here and add all of these callbacks and things. But you can have equally good developer experience with server components and their server util. And we will use that later on. But as I said, for this chapter, I just wanted to build like a very dirty, basic UI to ensure that we can actually create the new user. And now let's go ahead, create review, and merge this pull request.
So I'm going to go inside of my graph here. My apologies, my source control here. And I'm going to go ahead and add all changes. And before you come, you can open the branch whenever you want. So you can, for example, add the changes, make sure they are in stage.
Go ahead and click Checkout 2 and then create a new branch. So I'm going to call this 03-authentication-setup. I think that's the branch name. Yeah, authentication-setup. And the message will be the same.
You can see your branch is down here. You can click commit here and you can publish your branch as simple as that so your branch is now available for review let's go ahead and click compare and pull request and let's create a pull request and in a couple of seconds we will see the review by CodeRabbit. And here we have the summary. So, new features. We have introduced a complete authentication system with user sign-up, login and sign-out capabilities.
We have added a user interface for authentication including forms for registration and login, as well as conditional rendering based on the authentication status, a new API endpoint to handle authentication requests, and we have expanded the database schema. And of course, the new authentication library dependency. In here, we have a more in-depth walkthrough, as well as file-by-file change, and a sequence diagram explaining how our current form actually works. So you can see here that when we fill up the sign up or sign in form, we call the sign up or log in method which actually reaches the API ALF all route which then handles the ALF request and then using the to the database it validates or stores the user session and account entities and then it equally returns that state back to the user and the UI. Of course it left a ton of comments in regards to our form because that is just a temporary form which is missing a ton of things So naturally all of these recommendations are correct, but no point in resolving them because we will be deleting that entire component in place of a proper one here.
But if you're interested, you can pause and read just to see how this AI bot actually works because it is quite impressive as well as the suggestions it gives you. Excellent and it actually refactors like your entire component but we will be doing that later so no need to accept this. In here it adds some suggestions for our schema. And regardless if this is more correct or not, I don't want to change anything because I want this to be strictly compatible with BetterAuth. I don't want to, you know, accidentally mess it up.
Great. So in here it marked a potential issue. Sensitive credentials stored as plain text. I think that is a confusion because this is called text. That doesn't mean that what's stored inside is not encrypted, right?
It is just a text type. This is true. It could be a varchar with a token limit, but I think they do exactly that. They encrypt it, but they just store it under a text type from drizzle all of these other suggestions are semantic or new syntax here so I'm gonna go ahead and merge this pull request because I am satisfied with this result. Excellent.
Once you have merged this, go back to your IDE here and switch to your main branch. So you just have to find the origin main. And then just go ahead and click this and fetch origin here. And that should resynchronize everything here. When you go to your graph, there we go, you can see that We have added the database in the previous one, and in this one, we added the authentication setup and everything regarding authentication.
Let me just close package lock so you can see the actual code, like our session and our form, and we just merged that into main. You can, of course, go inside of your app page to confirm that you can see the code in here. Excellent! So that's it. We just merged our code.
You can always try this multiple times in case you think it's not synchronized for whatever reason. And that's it. Let's go ahead and mark this as completed. Amazing job and see you in the next chapter.