Next-auth v5
Sunday, January 5, 2025
•By Kanad Shee
Next-auth v5 with Prisma, OAuth, Email Verification, Reset Password, 2FA, and more

NextAuth v5
Integrating authentication into a modern web app can feel intimidating—especially when dealing with complex flows, third-party providers, and secure session handling. But with NextAuth.js v5, the process is not just manageable, it's downright seamless.
In this blog, I walk through how easy it is to set up NextAuth v5 in a real-world application. The new version brings a cleaner API, better TypeScript support, and a more flexible configuration system that aligns perfectly with modern Next.js App Router and Server Actions.
I’ve implemented it in my blog system to allow for a secure and extensible authentication flow without needing to reinvent the wheel. From handling credentials to integrating OAuth providers like GitHub and Google, the new v5 flow felt intuitive, declarative, and scalable. What’s more, the improvements in session handling and server-side logic allowed me to keep the app performant and secure, without overengineering anything.
Whether you're building a personal blog, a SaaS dashboard, or a community platform, NextAuth v5 is a drop-in solution that scales with your project. This post will show you how I made it work—and how you can too—with just a few lines of code and a focus on clean architecture.
Tools and Technologies
| Tool | Purpose |
|---|---|
| Next.js | App framework (App Router & Server Actions) |
| NextAuth.js v5 | Authentication library |
| Providers | Google, GitHub, Email & Password |
| Prisma | ORM & database client |
| Nodemailer | Email sending for verification / reset / 2FA |
| Zod | Input validation schemas |
| bcryptjs | Password hashing |
Init Project
Prisma Setup
- First install prisma by running
- Then initialize prisma in project:
-
Now it will create a prisma folder and will add an .env file in our project directory.
-
Add DB url in .env
- Add two models User and Account in schema.prisma file.
Note: Here make sure to make the password optional as for Google or Github there will be no password.
- Now, run the command to push schemas to db:
- After succesfully doing all the steps, run
-
We can see out created models in our localhost:5555
-
Now, install prisma client so that we can access all models throughout our project
- Now, we can use PrismaClient in our project like
Note: This is not the right way to do this as it will create a bunch of connection or a connection pool for each time request. So, rather than doing this, we'll do something else.
- Create a new file named prisma.ts inside the prisma folder and add the following code.
- So, now this will allow us to use the prisma variable throughout our application with one pool connection automatically.
ORM Ready
Auth Config
- First we have to install the latest version of next-auth
- Now, we have to install one more additional thing Prisma Adaptor from Auth.Js so that it can work with prisma.
-
Next, we have to make two files:
- auth.ts
- auth.config.ts
-
The auth.config.ts is created as in auth we can't use prisma as it it is not edge compatible.
and we will accquire this to auth.ts file
- Now, we have to make a route which will handle all requests inside app > api > auth > [...nextauth] > route.ts and add a simple line of code here.
- And also add one more secret in .env as AUTH_SECRET:
Providers
Google Setup
Go to console.cloud.google.com and get the OAuth client id and client secret and add them in .env file
- In similar way we can add GitHub also:
GitHub
NOTE: Make sure to add Homepage URL and Callback URL in getting the secrets for both the providers.
NOTE: Make sure to change the domain name after deployment
Shadcn
-
First we will create a custom sign up page.
-
Let's initialize shadcn for our project.
- Now, we will add some components from shadcn: button, form, card, label etc.
Register Page
- First, in the app folder create a route for register: app > auth > register > page.tsx
-
We'll make a client component RegisterForm as we're going to use hooks states etc.
-
Inside components dir, create another folder auth and make a component called register-form.tsx
- Now, make a schemas folders where we'll write zod validation and make a file named index.ts where we'll add our register schema.
-
Now, we will create some reusable components which we can use in both signin and register form. For ex: Inside @/components/auth,
- auth-header.tsx
- back-button.tsx
- form-error.tsx
- form-success.tsx
- card-wrapper.tsx
- forget-password.tsx
-
These custom compoenent now will be used in register-form or any other component as it needed.
-
Create a server action.
-
For that create a new dir as actions in root dir and create a file named register.ts
-
Now, we can use this server action in our register component.
-
Our final register component will be:
Here in place of loading we also can use useTransition hook of react also.
Login Page
- First, we've to make login schema.
- Now we have to make server action called login.ts
- Now, we have to complete the credentials login functionality in auth.ts file.
Credentials
-
This way with google and github we have added credentials configuration also.
-
Lets build custom buttons for Google and Github login.
-
For that first make the actions for those buttons
-
Google Login Action:
-
Lets create a component with two buttons Google and Github.
-
First we have made a custom Goggle-login button.
- and similar way Github-login compoent:
- Now, a component named Socials has been made:
Auth Complete
Callbacks
Callbacks Overview
-
First of all, as we are using strategy as "jwt", so we are going to use jwt callback
-
So, now we'll make two utility function which will be called inside this jwt callback
and
- Now, we have to configure our callback and session in auth.ts file:
jwt & session
NOTE: We do this stuff, as session is accessible in client side but jwt not so we can use user id or image to show their dp or any other stuffs as session is accessible to the client side.
-
Now, one more callback is there called signIn callback.
Use this signIn() callback to control if a user is allowed to sign in.
-
So, after adding signIn callback our auth.ts file will be:
signIn
Middleware
-
For setting up middleware, first we have to make a file named as middleware.ts file.
-
Now, we will make another file named routes.ts where we can specify our all private, public and auth routes like this:
- Now, in our middleware.ts file we can use these routes.
- Here the middleware run in all routes matching with the matcher config.
Middleware Note
Email Verification
Verification Schema
- First we have to add a new model as VerificationToken
- Now, run two prisma command for this model
- First, we have to search that is there any token present, if present check if not create one. So first make this function
-
These two function is going to use in the upcoming sections.
-
Now, we have to make a function to generate verification token for us.
- Now, we can use this function in our register and login server action.
- Similarly, we can do this for login server action also.
Mailsender (Nodemailer):
We have to make a function to send email using Nodemailer package.
-
We have made this function dynamic for all our upcoming process for verifying email, resetting password and Two factor authentication.
-
Now before signIn callback run we have to check if the user email is verified or not. If yes then proceed else let the user to verify their email first.
-
This way we will restrict the user to verify his email before signin.
-
In same way we can send this email after any user register
-
Now, we have to make a server action to verify our email.
-
First lets make two utility function that needed for this.
- getVerificationTokenByToken and
- getUserByEmail
and
- Now, we can use these two utulity in our email-verification server action.
- Now we've to make a custom email-verification form page
We've use this form inside app > auth > email-confirmation > page.tsx
So, this way we can verify our email.
Reset Password:
Reset Password Schema
- For this functionality, we can build a new schema
- Now we have to make some utility function.
- Now, we can use these function inside the token.ts file inside lib
Generate Reset Password Token
- Now, we can use this password generating token function in reset-password server action
- Now, we can use this server action inside the reset-password-form.tsx.
This way we can reset our password successfully.
TWO Factor Authentication:
Two Factor Schema
- First we have to add and do some changes in our schema.prisma file
- These changes has been done in schema.
Note: Now after changing schemas don't forget to run:
- Now, lets create a utility file for two factor token:
- Now, one more utility function is needed to know about two factor confirmation for an user.
- Now, we have to make a function in tokens.ts in lib which will be used in server action.
-
In mailSender.ts we have configured email template for 2FA.
-
Now, we'll modify our login.ts server action and auth.ts file.
-
Here, we're returning twoFactor: true to the frontEnd so that we can render a form to enter two factor code.
-
These porition of code is modified in login.ts file and in signIn callback:
- Here is a diragram how its working
So, here the 2FA authentication has been done successfully.
Now, here the full Next-Auth is done properly and now some extra frontend staffs are done
Things to remember:
next-auth.d.ts
-
Here, we have added some more user details in session in auth.ts file.
-
So, according to the documentation of Auth.js, we can add one more file next-auth.d.ts file and there we can add those fields types in the user and can export that and can be used throughout the application.
-
For ex:
Extend User Type
- And now, we can use this file in our components
- Here just how we have used it in user-info.tsx file in uils/user-info.tsx file.
So, this way we can use next-auth in our project and after deployment don't forget to change the callback url and homepage url in GitHub and Google Console OAuth configuration.