Database Session Authentication with Prisma & NextJS App Directory

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everyone and welcome to my Channel today we are going to be learning about nextjs authentication with Prisma and database sessions we'll be using next off that's a package for nextjs authentication we'll be creating a Prisma client extension to query the database for the current user based on the current user session let's dive in first things first just want to show you the UI this is the application that we're going to be building and as you can see we've got a home and me and a protected navigation we got a signin button and currently we're not signed in we click me we're not signed in we click protected we have access denied and so let's start by signing in if I just enter my email address here and then I check my email I have a magic link if I just copy this link from the email I received click here and you're authenticated and now if I click me we are signed in if I click protected we can see here this is now accessible and if I sign out there we go I'm signed out click me not signed in protected access Deni so we're going to be building this and it's pretty simple but I think just with these three tools next o nextjs and Prisma we can we can do a lot so let's get started first things first we're going to open the terminal run npx create next app we're just going to call it my app we are going to use typescript es lint Tailwind I'm not going to have a source directory we're using the app browser and we will create a custom import Alias for EXT for/ that just means we can use this to access any of the directories in the codebase using that path Okay so we've installed the next app now we're just going to open it by running code my app we're going to start by removing yarn and uh we do that by running this command we're going to install everything with bump okay now that we've we've installed everything with bun let's just delete the public folder and the file icon we don't need that let's start by updating the page and layout in nextjs this is provided by the create next app command we just want to get rid of all of this for now we are going to go into the layout and we can put our main tag here main okay so let's start by installing some of the necessary packages so there's quite a few that we need to install let's do FN add Prisma adapter next off Prisma Prisma client clsx class variance Authority node mailer and I think that's it now we can update the app and layout let's just start by adding clsx here and we want to make this and now let's just add some text content to this page hello this is my app run bun Dev there we go we've got our app okay so the next step is to create our database and you can do that using a psql command so you have to have psql installed on your computer before you can do this but the command is create DB and you can just type in any name and I've already done this for a uh postgress data space which is what we'll be using for this video and you create the database as you can see I already created it that will create the database you probably need to go in there and run some commands such as Grant all privileges on schema public to rout and alter schema public owner to rout and that is just to allow the public schema to be accessible by the root user which is who we have created in this psql environment if I just exit this as I've already done that we are clear our terminal and so now we have a database so the next step is going to be to create a Prisma schema let's create that prismark schema. prismark now we need to start by creating our client so we do generator client provider equals Prisma client JS data source DB postgressql perfect now we need to create our user and GitHub copilot has kindly done that for us we will just take what it has there we also need to create session let's see what it's got excellent and we also need to create a verification token let's just update this because we do not have post and instead we can call that sessions and I generally like to make everything lowercase so we can just do this create in the database I just prefer this and if we do M to users and we can remove this name now let's do the same for our sessions we do map create app map updated app we should also add a token here and that needs to be unique cool I think we are pretty much there with our Prisma schema other than mapping this to user ID mapping this now what we will need to do is run fun Prisma DB push and that brings us to our next configuration we need to set up so we're going to create a.lc file and this is where we're going to store our environment variables I actually have these environment variables so I'm going to go and take them from somewhere okay so we have our database URL our next or secret and our email server email from I'm going to get these from my older environment you're going to have to create these yourselves which is effectively using an email service provider to create a URL that allows you to use that as server that sends emails so generally with the email service provider you will have like a URL that begins with SMTP I use resend but that is another topic that we'll cover in another video so now if we run source. .lo bun Prisma DV push there we go you can see that has pushed our schema to the database so if we take a look this is the database we created we've got the root the password and that's just a local user that we've created on the database the port for postgress is 5432 that is Local Host and let's just test this connection okay it looks like we have not made our verification token mapped so let's do that quickly and if we run Prisma DB push refresh and there we go that just looks much neater now that we've created our schema we need to create our client and we'll do that by creating a lib directory a new file called db. TS we start here by importing Prisma client we do const Prisma equals new Prisma client const Global for Prisma equals Global unknown as Prisma Prisma client then we'll do export const DB equals global. for Prisma or Prisma and that's just the way that we have to set this up based on the Prisma documentation and then if we do if process. does not equal production then we set the global for Prisma Prisma now that we have our Prisma set up we can now access the DB variable throughout our application in order to query the database so the next step is to create our next off configuration and what we want to do is we want to create a new file called off. TS and this is going to export cons options equals and we want this to satisfies options cool so that basically says it doesn't satisfy what is required in the options which is a nice little way to get some type safety we'll start by adding our providers and we want to use the email provider and this is where our server comes in so as you can see it's autop populating and we just want to delete this because we are using process. emp.a server that allows us to send emails and this is the from address which we send emails from the reason we need this is so that we can access our magic link when we sign in next next we will create our secret which we added to our environment variables and then we'll add our adapter for Prisma we want to put in our recently created DB like that as you can see we're exporting our DB and we're putting it into the Prisma adapter now we're going to use session and we do not want JWT we instead want to use strategy database and the max age can be 30 days we want to build custom Pages for our signin form and for our verification request because out of the box next off gives you some basic ones but they're you know not very unique and they're also off the page that we want to keep them on so let's create Pages sign in and verify request these pages are actually created by next off and we override them by adding them here now we want to actually create some call backs call back for us but we'll just do async session we want to get the user from the session and then we want to return the user we also need to get the session we want to do session. user equals user now why is this shouting us we have to add email verified that is going to be a date time and we want it to be optional we also need to add a session token we can map that so why is this happening let's have a look I found out wire session is doing this and that is because we were returning the user and we want to return session now we've got our call back it assigns the adapter user to our session and then we want to add our events we want to have a sign in event we can just log something here user signed in okay I'm happy with that so our next step is to add a new folder in here called API and within that we add off within that we add next off and we create what's called a route Handler in nextjs in this route Handler we are going to import next both in import our options and we're going to const Handler equals next all pass in our options we're going to export Handler as get Handler as post so I think we' set everything up now from the authentication and the Prisma side next step is to create some components some react components so back to our page let's start creating some components we'll going to our layout what we want to do is we want to add a header component so we're going to create a new folder called components we're going to create a header TSX make this use client because we're going to be doing some signing out from the header and to do that we need to use next offs sign out method that they export and those can only be used on the client side import link X link import sign in sign out use session react we'll import the use router from next navigation so export default function header we'll return a header element this is the header let's just check if this works it's run B def great it's there now what we want to do is we want to get the session from there and con brouter equals H brouter and actually we want to port with status from here I want to do cons loading equals equals loading okay so we got our session which is either going to be session or null got our router for navigation and we've got our loading State the next step is to create a provider and what provider does is it allows you to access the session from the use session hook that next off provides provider is going to wrap part of our application and what we're going to do is we're going to just get it to wrap the header let's get started creating the provider so provider.com TSX export default function provider we're just going to return the children react. props with children find as a rapper for the header figher now we want to get the session from the server we do con session equals get server session make this async export default async function and we want to wait this as this returns a promise and we can pass in the session here and so we'll need to accept the session as well so interface provider props extends we want the session to be session from next off or now and then what we need to do we need to do session provider session equal session cool so that keeps our provider wrapping the header and giving it access to this new session Hood as well as the sign in and sign out methods as they are not accessible on the server so let's continue with our header we want to create some navigation links we've got our navigation here for home me protected and we have our sign in and sign out buttons and we're using sign out method here and then pushing we have not signed in and if there is a session we're authenticated get rid of all this there we go and we can have loading B gray e Gray the next step is to create our signin component we still need to create these Pages we can do that by creating sign in. TSX so we'll Begin by making this a use client we'll export default function sign in return now we're going to create some reusable components at label and input just create a label TSX and an input already have these so just get them and as you can see we're missing a package so fun react label excellent so now we can use them in our signin component we'll start by importing the label and the input and we'll also import signin from next off react we also need to import use state so let's get started building our signin component by adding this we want to have a a loading BSE and then we want to create a form inside that form we'll have a div a label and the label have HTML 4 equals email input ID equals email name equals email placeholder type equals email on change needs to be wrapped in set email let's add some Styles class name equals space y4 w96 we should also add on submit equals we can create a function handle submit F handle submit set loading sign in in why is this shouting at me passing generics to a type form event we can also just change this to me now we need to just create a submit button button disabled equals loading send me a magic link and I'll just add type equals submit and some Styles this leads nicely to creating a page for signin so if we do new page signin page. TSX move this into the off folder off sign in just add the sign in component there we go now we should be able to see that in the UI we go to sign in there we go it's looking good next we need to add a verify request page which will look like this as you can see the page names here actually directly map to the pages we have here we're effectively overwriting them and let's have a look how that looks nice so that is our custom verify request page now we're going to create our access denied component and access deny TSX and we've created this access deny component and what we can do is we can add a page called protected protected will be a page. TSX so this route protected is going to be our page that you have to be signed in in order to access and so we will import the access denied font protected equals async and we are going to return the access to I component however that does not make our component secure just yet so to make this component secure concession equals away get server side session we pass in our options and then we need to return access to denied if no session return access denied otherwise we return the user and we can export default protected now all of this code is going to be available to you the GitHub link that I post down below so please feel free to check it out let's take a look protected access denied you must be signed in to view this page now we need to create the Mi page so let's just do me and page. TSX const me equals async export default let's just call it me page let's take a look and so what we want to do here is we want to use the Prisma client extension to get the current session so let's start by doing const user equals and we're going to create this db. current do user function using Prisma CLI extensions so let's get into that we need to go to our lib we can add a new folder extensions let's do current user. TS we need to import the options from or because we need to get the session we need to import Prisma from Prisma client and we need to import the server session from next off now this how we create a Prisma client extension let's start by exporting a function called current user and then we want to return Prisma do Define extension and then we want to get the client and return from the client client. extends Open brackets and we want to access the model the model we want to access is user and we want to async current user and there we go as you can see we've been helped out here by GitHub co-pilot however it is wrong we need to if no session. user. email then we return null because the user doesn't have an email and that's how we're getting them to authenticate and we just need to return the user and it's as simple as that now we've created a current user extension and what we can do now is we can use this name here however let's just call it current we can now export this into our Prisma client we need to pass in the options here so there we go we need to update this a little bit to get it to work so let's do do extends and we import current user we call that function there as you can see It's shouting at us so we need to basically change this to type of Prisma so we're getting a blue squiggly here but I think it's fine that is from the total typescript package in our OJs we have to also as Prisma client OJs does not like us using the extends because it doesn't have compatibility however this will work let's test this out we have go back to our Mi page we want to await db. current. user sorry db. user. current as you can see that is now a new function and it gets us the user so we've got our user we can say if no user redirect to let's just say sign in and if there is a user let's say signed in as user. email okay so I found something out and that is we are not passing in the options into here and we need to add the sign out here we need to keep that here so back to checking our Mi query let's have a look can we see the user from the get current when I click on me I get a promise pending thingss to be awaited try that again user is null okay so now if I sign in send me a IC link so we've signed in and there we go we've got our user so we can now say if no user redirect to off sign in and if we go to our signin page let's go to sign in page page we want to do const user equals wa db. user. Curren if user redirect so we've got signin page redirecting them if they're already signed in and the Mi page we can say I am signed in as user. email we don't think to make that optional let's have a look I'm signed in as there we go we're getting the user from the database we are able to access the protected page we have home and then if we sign out we try and access this it redirects me to sign in protector says access denied and there you have it so that is the application and I hope you found this video helpful if you did please don't forget to give me a thumbs up and subscribe and I look forward to sharing more educational content with you
Info
Channel: Taylor Lindores-Reeves
Views: 5,852
Rating: undefined out of 5
Keywords: NextJS, Authentication, Postgresql, Prisma, NextAuth, Database, Sessions
Id: _WJA0QFb-AU
Channel Id: undefined
Length: 23min 1sec (1381 seconds)
Published: Sun Oct 22 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.