# Next.js Email Authentication using NextAuth

> Learn how to add email-based authentication to Next.js with NextAuth.js, from configuring an SMTP email provider and JWT sessions to the useSession hook.

Author: [Flavio Copes](https://flaviocopes.com/about/) | Published: 2021-05-17 | Updated: 2022-02-10 | Topics: [Next.js](https://flaviocopes.com/tags/next/) | Canonical: https://flaviocopes.com/nextjs-email-authentication/

Managing authentication in [Next.js](https://flaviocopes.com/nextjs/) can be done in many different ways. 

In my site I chose to implement email-based authentication with JWT tokens via [NextAuth.js](https://next-auth.js.org) and here's how I did it.

An external database is needed. You can use a local database, or a cloud one. I chose PostgreSQL but you can use anything you want.

I suppose you already have a Next.js website up.

Run `npm install next-auth pg` to install NextAuth and the PostgreSQL library. 

Then add to your `.env` file:

```
DATABASE_URL=<enter URL of the postgresql:// database>
EMAIL_SERVER=smtp://user:pass@smtp.mailtrap.io:465
EMAIL_FROM=Your name <you@email.com>
NEXTAUTH_URL=http://localhost:3000
SECRET=
```

Make sure you add a SECRET code. You can use https://generate-secret.vercel.app/32 to generate it.

I use https://mailtrap.io to test the emails, it's quite handy while you are setting things up.

Create a `pages/api/auth/[...nextauth].js` file with this content:

```js
import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'

export default NextAuth({
  providers: [
    Providers.Email({
      server: process.env.EMAIL_SERVER,
      from: process.env.EMAIL_FROM,
    }),
  ],

  database: process.env.DATABASE_URL,
  secret: process.env.SECRET,

  session: {
    jwt: true,
    maxAge: 30 * 24 * 60 * 60, // 30 days
  },

  jwt: {
    secret: 'INp8IvdIyeMcoGAgFGoA61DdBglwwSqnXJZkgz8PSnX', //use a random secret token here
    encryption: true,
  },

  debug: true,
})
```

Now it depends a a lot on your data access layer. If you use the [Prisma](https://flaviocopes.com/prisma/) ORM, also install `@next-auth/prisma-adapter` with 

```
npm install @next-auth/prisma-adapter
```

and include it in `[...nextauth].js`:

```js
import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'
import { PrismaAdapter } from '@next-auth/prisma-adapter'
import prisma from 'lib/prisma'

export default NextAuth({
  providers: [
    Providers.Email({
      server: process.env.EMAIL_SERVER,
      from: process.env.EMAIL_FROM
    })
  ],

  database: process.env.DATABASE_URL,
  secret: process.env.SECRET,

  session: {
    jwt: true,
    maxAge: 30 * 24 * 60 * 60 // 30 days
  },

  jwt: {
    secret: 'INp8IvdIyeMcoGAgFGoA61DdBglwwSqnXJZkgz8PSnX', //use a random secret token here
    encryption: true
  },

  debug: true,
  adapter: PrismaAdapter(prisma)
})
```

You need to add 4 models to your `schema.prisma`:

```
model VerificationRequest {
  id         String   @id @default(cuid())
  identifier String
  token      String   @unique
  expires    DateTime
  createdAt  DateTime @default(now())
  updatedAt  DateTime @updatedAt

  @@unique([identifier, token])
}

model Account {
  id                 String    @id @default(cuid())
  providerType       String
  providerId         String
  providerAccountId  String
  refreshToken       String?
  accessToken        String?
  accessTokenExpires DateTime?
  createdAt          DateTime  @default(now())
  updatedAt          DateTime  @updatedAt
  user               User      @relation(fields: [userId], references: [id])
  userId             Int
  @@unique([providerId, providerAccountId])
}

model Session {
  id           String   @id @default(cuid())
  expires      DateTime
  sessionToken String   @unique
  accessToken  String   @unique
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt
  user         User     @relation(fields: [userId], references: [id])
  userId       Int
}

model User {
  id            String    @id @default(cuid())
  name          String?
  email         String?   @unique
  emailVerified DateTime?
  image         String?
  createdAt     DateTime  @default(now())
  updatedAt     DateTime  @updatedAt
  accounts      Account[]
  sessions      Session[]
}
```

> Remember to run `npx prisma migrate dev` any time you modify the schema to apply the changes to the database.

Now open `pages/_app.js` and add

```js
import { SessionProvider } from 'next-auth/react'
```

And wrap your `<Component />` call:

```js
return <Component {...pageProps} />
```

with it:

```js
return (
<SessionProvider session={pageProps.session}>
  <Component {...pageProps} />
</SessionProvider>
)
```

Now add into your app a link that points to `/api/auth/signin`. This will be the login form.

Finally, in pages you want to require a logged in session active, you first import the `useSession` hook:

```js
import { useSession } from 'next-auth/react'
```

Then you use that to gather information on the state. `loading` is true when the session info is still loading.

```js
const { data: session, status } = useSession()
```

We can use this `session` object to print information on screen when the user is logged in:

```jsx
{session && (
  <p>
    {session.user.email}{' '}
    <button
      className="underline"
      onClick={() => {
        signOut()
        router.push('/')
      }}
    >
      logout
    </button>
  </p>
)}
```

We can also use that information to not return anything unless we finished loading, and unless the session is established:

```js
if (typeof window !== 'undefined' && loading) return null

if (typeof window !== 'undefined' && !session) {
  router.push('/api/auth/signin')
}

if (!session) { //for server-side rendering
  return null
}
```

I send the browser to `/api/auth/signin` if the user is not logged in. You can also create a custom form if you want, but those are the basics.

Server-side, you use 

```js
import { getSession } from 'next-auth/react'
```

then 

```js
const session = await getSession({ req })
```

to get the session data, either in an API route or inside `getServerSideProps({ req })`.

That's how I use NextAuth for a very basic authentication setup.

The NextAuth package is very complete and provides tons of options and customizations, check them out on <https://next-auth.js.org>.
