Adding Authentication to an existing serverless Next.js App in no time with NextAuth.js!
Tags: nextjs, auth, nextauthjs, oauth
Published: 2020-10-24 23:08:25

---
title: Adding Authentication to an existing serverless Next.js App in no time with NextAuth.js!
published: true
description: Using NextAuth.js to add serverless OAuth based authentication to a Next.js application lickity-split!
tags: nextjs, auth, nextauthjs, oauth
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/x6ta92tq8n2wfoszs13r.png
---

> Updated 25.05.21 with latest NextAuth.js examples / best practices / links

Do you have a Next.js application and you'd like to add user / authentication support? Well look no further! All you need is `NextAuth.js`, some OAuth keys from your favorite provider (Google, Github, etc.) and about 5 minutes of your time!

Let's summarize what we're going to do here before we get started. 

We're going to do the following things in this tutorial:
1. Create  OAuth keys in the Google Developer Portal
2. Install and configure NextAuth.js into our Next.js application
3. Protect some page routes and api routes

Let's get started!

## Prerequisites

I'm going to assume you have the following already:
1. A Google Account
2. An existing Next.js app

### Google OAuth Setup

So first we have to obtain our OAuth clientID and secret from Google. NextAuth.js has built-in support for a ton of OAuth providers like Apple, Discord, Facebook, Github, Google, LinkedIn, Okta, Slack, Twitch, Twitter, and a ton more which you can find in their [docs - providers](https://next-auth.js.org/configuration/providers). There are instructions on how to retrieve the required OAuth keys for all providers there, but I will only go into detail for how to setup Google here.

First, visit https://console.developers.google.com/apis/credentials.

If you don't have a project setup in Google's developer console yet or you want to create a new one for this application, go ahead and select the project overview in the top left, and click "Create Project"

![Create Project](https://imgur.com/Ox8TGh4.png)

Once you have the project created, make sure you're in the "API's & Services" -> "Credentials" section of the left-hand main menu. There, select "Create Credentials" and select "OAuth client ID".

![Create Credentials](https://imgur.com/Q9TH8QC.png)

> If you've not yet gotten the OAuth consent screen setup for your domain, you'll have to do that first - just enter a name for the app and the domain you'll be using for it. For Internal applications there is no Google verification process necessary, but it will also only allow members of your G Suite domain to use the application. Public applications must have the domain verified by Google before large scale sign-in is allowed - OAuth is limited to 100 "sensitive scope logins" i.e. test logins until the consent screen is verified by Google.

Next, select "Web Application" for the type of OAuth Client ID we'd like to create, and give it a name. You'll also have to enter a URI for **Authorized Javascript Origins** and **Authorized redirect URIs** here. 

The **Authorized Javascript Origin** is simply the domain of your application, for example `myapp.domain.com`. 

The **Authorized redirect URI** will vary depending on which provider you're setting up, but for NextAuth.js's default setup with Google as your OAuth provider, the redirect URI will be something like: `https://myapp.domain.com/api/auth/callback/google`. Obviously make sure to adjust the domain to whatever you're running your application under, the important part is the `/api/auth/callback/google` path.

![Create OAuth Client](https://imgur.com/3wd99X2.png)

After you press "Create", you'll get your **OAuth Client ID** and **OAuth Secret**! Make sure to save these somewhere because we'll need them later!

### NextAuth.js Install

Next, we're going to need to install NextAuth.js into our Next.js application. So for that, navigate to your project directory and install `next-auth`.

```bash
cd /opt/dev/my-nextjs-app
npm i -s next-auth
```

Now we're ready for the NextAuth.js setup!

## Initial Setup

Now that we've got all the prerequisites and dependencies out of the way, lets get the config file for NextAuth.js setup. First, we'll need a `.env` file in the root of your project directory if you don't have one yet.

Your `.env` file should contain the following:

```bash
NEXTAUTH_URL=https://myapp.domain.com
GOOGLE_ID=abc123
GOOGLE_SECRET=abc123
```

> The `NEXTAUTH_URL` is the URL at which your application will be running. You can set multiple URLs for different environments by setting up multiple `.env` files, like `.env.production`, `.env.development`, etc. The same is possible in almost any hosting provider's environment variables setup section (i.e. with Netlify or Vercel, etc.). The `GOOGLE_ID` and `GOOGLE_SECRET` are our OAuth keys we received from the Google developer console earlier!

Next, create a Next.js API route for authentication at `pages/api/auth/[...nextauth].js`. This file should contain at least the following:

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

const options = {
  providers: [
    Providers.Google({
      clientId: process.env.GOOGLE_ID,
      clientSecret: process.env.GOOGLE_SECRET
    }),
  ],
  debug: false
}

export default (req, res) => NextAuth(req, res, options)
```

There's a lot more you can configure here, but this is the minimum requirements for JWT based OAuth authentication. More config options can be found in the [docs - configuration](https://next-auth.js.org/configuration/options), as well as a fully annotated version of this file [here](https://github.com/nextauthjs/next-auth-example/blob/main/pages/api/auth/%5B...nextauth%5D.js).

The keen eyed among you will notice we did not specify any sort of database here. This means a few things:

1. JWT Support is enabled by default for session handling
2. We do not have a permanent database of users

If you'd like to permanently store the users/accounts in a database, NextAuth.js makes it really easy to add sqlite for testing or various other adapters such as MySQL, Postgres, MongoDB (via TypeORM), FaunaDB, Firebase, DynamoDB, and Prisma. More information on database details can be found in their [docs - adapters](https://next-auth.js.org/adapters/overview).

Next, you'll also want to wrap your app in a NextAuth provider, so open up your `pages/_app.js` or create one if you don't have one yet.

It should end up looking something like this:

```jsx
import { Provider } from 'next-auth/client'

export default function App ({ Component, pageProps }) {
  return (
    <Provider session={pageProps.session}>
      <Component {...pageProps} />
    </Provider>
  )
}
```

By wrapping your whole application in this provider, we can use React Context to make a `useSession` hook available in any page / component in your app and share session state.

Believe it or not, this is all that's needed for a basic Google OAuth setup with NextAuth.js!

The library includes some basic Login / Logout pages by default, so there's no need to write them. If you'd like to customize those, that is of course supported. Please take a look [here](https://next-auth.js.org/configuration/pages) for more details.

The last thing we're going to do in this tutorial is to show how you can actually restrict access to pages to authenticated users only. 

Currently users can still navigate to any route in our app and will get everything rendered no matter their logged in status because we're not conditionally rendering anything yet.

## Restricting Page Access

First, let's build a little `AccessDenied` component which we'll show the user if they land on a protected route and have not logged in yet. This will tell them they do not have access, and give them an opportunity to sign-in.

Lets name this, `components/accessDenied.js`

```jsx
import { signIn } from 'next-auth/client'

export default function AccessDenied () {
  return (
    <>
      <h1>Access Denied</h1>
      <p>
        <a href="/api/auth/signin"
           onClick={(e) => {
           e.preventDefault()
           signIn()
        }}>You must be signed in to view this page</a>
      </p>
    </>
  )
}
```

Finally, on our pages that we want to protect, we just need to import the `useSession` hook from `next-auth` and check for the session before returning the page contents, showing the `accessDenied.js` component if there is no session available.

### Client-side Page

An example protected client-side rendered page (i.e. `pages/index.js`) may look like this:

```jsx
import React from 'react'
import { useSession } from 'next-auth/client'
import Layout from '../components/layout'
import AccessDenied from '../components/access-denied'

export default function Page () {
  const [ session, loading ] = useSession()

  // When rendering client side don't display anything until loading is complete
  if (typeof window !== 'undefined' && loading) return null

  // If no session exists, display access denied message
  if (!session) { return  <Layout><AccessDenied/></Layout> }

  // If session exists, display content
  return (
    <Layout>
      <h1>Protected Page</h1>
      <p><strong>Welcome {session.user.name}</strong></p>
    </Layout>
  )
}
```
### SSR Page

And an example SSR page may look like this:

```jsx
import { getSession } from 'next-auth/client'
import Layout from '../components/layout'
import AccessDenied from '../components/access-denied'

export default function Page ({ session }) {
  // If no session exists, display access denied message
  if (!session) { return  <Layout><AccessDenied/></Layout> }

  // If session exists, display content
  return (
    <Layout>
      <h1>Protected Page</h1>
      <p><strong>Welcome {session.user.name}</strong></p>
    </Layout>
  )
}

export async function getServerSideProps(context) {
  const session = await getSession(context)

  return {
    props: {
      session
    }
  }
}
```

### API Route

And finally, an example protected API Route may look like this:

```js 
// pages/api/protected.js
import { getSession } from 'next-auth/client'

export default async (req, res) => {
  const session = await getSession({ req })

  if (session) {
    res.send({ content: 'This is protected content. You can access this content because you are signed in.' })
  } else {
    res.send({ error: 'You must be signed in to access this api route' })
  }
}
```

## Conclusion

Alright everyone, I hope that didn't take much longer than the promised 5 minutes!

This example can be deployed to Vercel for example, as NextAuth.js is compatible with their serverless api functions.

I'd also be remiss if I didn't mention that alongside built-in support for the many OAuth providers I mentioned in the introduction, there is also built-in support for Email based "magic link" sign-in as well as options for adding custom OAuth providers and other custom authentication providers, including a [great tutorial](https://next-auth.js.org/tutorials/ldap-auth-example) detailing how to use LDAP.

I want to thank @IainCollins and @balazsorban and all the wonderful contributors to [NextAuth.js](https://next-auth.js.org) for their great work! This post was based mostly off the example app and my experience using NextAuth.js in 2-3 Next.js applications as well as contributing to the project over the last few months. 

You can find more information in the official NextAuth.js example application [here](https://github.com/nextauthjs/next-auth-example).

Further Reading
---
- [NextAuth.js Homepage](https://next-auth.js.org)
- [NextAuth.js OAuth Providers](https://next-auth.js.org/configuration/providers)
- [NextAuth.js Database Adapters](https://next-auth.js.org/configuration/databases)
- [next-auth npm](https://npm.im/next-auth)
- [next-auth-example](https://github.com/nextauthjs/next-auth-example)
- [FAQ](https://next-auth.js.org/faq)