Adding email authentication to NextAuth

I'm a full-stack developer from South Africa 🇿🇦. I love writing about JavaScript, HTML and CSS.
Search for a command to run...

I'm a full-stack developer from South Africa 🇿🇦. I love writing about JavaScript, HTML and CSS.
No comments yet. Be the first to comment.
Most of you know me for my consistency, a golden arrow in my blog series. I've written 1000 articles in 1008 days! Almost an article a day, and my honeymoon was the only holiday I ever took. I'm super proud of this achievement; it has been a fantasti...

It's not the first time I'll be talking about community. I think it's an essential aspect of any successful tool. This shows in my previous explorations of Astro, Medusa, and now Vendure as well. All these products thrive in a super open, welcoming, ...

The cool part about Vendure is how easy it is to set up and how abstract each layer is. Basically, we get the following elements: External database Server Worker Admin UI Frontend While this is amazing, it also brings a bit of complexity when it co...

The previous article looked at customizing Vendure on a data and process level. In this article, we'll look at customizing emails, as they are often a big part of a webshop system. We'll be looking at two different layers of customization for customi...

Even though Vendure is a pretty significant project out of the box, in some cases, we might want to go in and modify some elements to work to our specific use case. In this article, I'll take a high-level look at some elements we can customize within...

We had a first look at NextAuth, a super simple way to add authentication to your Next.js app.
We chose a social login that time, but we can also roll out email authentication!
We need to have a database setup. We will be using the Postgres database we created on Heroku.
For the ease of this tutorial, I'll start from scratch so that it's easier for you to follow along.
Let's create a new Next.js app:
npx create-next-app
Then we need to add all the dependencies:
npm install next-auth@beta @prisma/client @next-auth/prisma-adapter@next
npm install prisma --save-dev
At the time of writing, I had some issues installing the Prisma adapter version, so I used
--legacy-peer-depsfor now.
And on sub-note two, it should install nodemailer, but I needed to add it manually.
npm install nodemailer
We need quite some administrative environment variables, so let's get started by setting those up.
Open/create the .env file and add the following fields.
DATABASE_URL="postgres://..."
EMAIL_SERVER=smtp://{user}:{password}@smtp.mailtrap.io:587
[email protected]
NEXTAUTH_URL=http://localhost:3000
Let's start by creating our prism schema for the authentication layer.
Run the following command to generate the primary Prisma folder.
npx prisma init
In there, add the following schema that is needed for NextAuth.
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String?
access_token String?
expires_at Int?
token_type String?
scope String?
id_token String?
session_state String?
oauth_token_secret String?
oauth_token String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
}
model Session {
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
}
model VerificationToken {
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
}
You can then go ahead and run the following command to publish the database.
npx prisma db push
// Or this one if you are following migrations
npx prisma migrate dev
Once it's done, we should see all the fields in the database.

The next thing we need to do is the standard NextAuth config, so let's set that up quickly.
First, we'll need an API file to handle all the logic for us. Create an auth folder inside your pages/api directory.
In there create the [...nextauth].js file.
import NextAuth from 'next-auth';
import EmailProvider from 'next-auth/providers/email';
import { PrismaAdapter } from '@next-auth/prisma-adapter';
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
export default NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
EmailProvider({
server: process.env.EMAIL_SERVER,
from: process.env.EMAIL_FROM,
}),
],
});
Here we set the NextAuth to work with the Prisma database adapter and use the email provider. These two combined enable us to store users in our own Postgres database.
Then we need to wrap our app with the session provider.
Open up the _app.js file and make it look like this:
import '../styles/globals.css';
import { SessionProvider } from 'next-auth/react';
function MyApp({ Component, pageProps: { session, ...pageProps } }) {
return (
<SessionProvider session={session}>
<Component {...pageProps} />
</SessionProvider>
);
}
export default MyApp;
The last part is the frontend page, so open the index.js file and change it to this:
import { useSession, signIn, signOut } from 'next-auth/react';
export default function Component() {
const { data: session } = useSession();
if (session) {
return (
<>
Signed in as {session.user.email} <br />
<button onClick={() => signOut()}>Sign out</button>
</>
);
}
return (
<>
Not signed in <br />
<button onClick={() => signIn()}>Sign in</button>
</>
);
}
Now let's try it out and see what happens.
Run the app npm run dev and click the login button.

If you used Mailtrap, the mail should show up there like so:

Once we click the sign-in button, we should go back to our app and be logged in!

And if we open our database, we can see the user created in there.

Pretty cool, we now rolled out our own authentication layer for NextAuth based on email.
You can find the complete code on GitHub.
Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter