SaaS Project Update 3 - Adding Authentication to my Next.js/Prisma/Postgres Project
Tags: webdev, javascript, showdev, buildinpublic
Published: 2021-06-09 00:26:50

In this series, I'm building a Software-as-a-Service product for syncing environment variables between team members. Since my background is mostly frontend, I'll be learning about backend technologies on the way. You can read more about my concept and technology selection in the first post, and you can read about my project setup in the second post.

## Adding Authentication

The project needs authentication so that users can securely access their organizations, projects, and environments. I'm planning on adding an extra level of encryption for the environment variables themselves, because they need to be extra secure to protect sensitive + powerful API keys and other environment variables. We'll get to that in a later post.

⚠ Authentication is a super tricky feature to get right - there are layers upon layers of complexity and security to consider, too much for most projects to handle well. Generally it's a best practice not to build your own authentication system - there's lots of info online on why that is, but see [this article](https://dev.to/jordanfinners/make-one-resolution-this-year-never-write-your-own-authentication-3nc1) for some examples.

## Next-Auth

I started researching authentication solutions. Auth0 is one of the most popular systems in this area - https://auth0.com/blog/create-a-simple-and-secure-node-express-app/

However, reading through the tutorial, I decided I needed something more packaged, so that I would handle even less of the auth and security in my code.

Soon, researching by ~~a serious scientific process~~ googling topics like "Nextjs auth system," I found [Next-Auth](https://next-auth.js.org/). Next-Auth is an open-source authentication system for NextJS apps. It's super flexible, and compatible with many authentication providers (which I'll explain in a minute) and multiple database systems, including postgres.

![List of compatible providers for Next-Auth](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x7lsw2o5mmt8uh80378n.PNG)

### Next-Auth Setup

We need to connect an "Authentication Provider" to Next-Auth. The best way to explain "authentication providers" is through an example: when you go to a new site and see "Sign in With Google," **Google is acting as an authentication provider** for that site. You essentially create an account for the new site by signing-in through Google, which provides credentials to the new site.

I decided to use GitHub as my first authentication provider, which will work well because this is a tool made for developers. With Next-Auth, I can always add a new provider later. I followed the Next-Auth guides for the GitHub provider and the Prisma adapter.

First, `npm i next-auth @next-auth/prisma-adapter@canary`.

(Note: If you're following along, don't miss the `@canary` or you'll have an outdated package with different usage than the current version!)

Then I created this file: `src/pages/api/auth/[...nextauth].js` with this content:
```js
import NextAuth from "next-auth"
import Providers from "next-auth/providers"
import { PrismaAdapter } from "@next-auth/prisma-adapter"
import { PrismaClient } from "@prisma/client"

const prisma = new PrismaClient()

export default NextAuth({
  providers: [
    Providers.GitHub({
      clientId: process.env.GITHUB_CLIENT_ID,
      clientSecret: process.env.GITHUB_CLIENT_SECRET
    })
  ],
  adapter: PrismaAdapter(prisma),
})
```

To get the `GITHUB_CLIENT_ID` and `GITHUB_CLIENT_SECRET`, you can go to GitHub, click your profile picture in the top right corner, click `Settings` in the dropdown menu, click `Developer Settings` on the left-hand menu, and then go to `OAuth Apps` and create a new OAuth App. Enter your project information, and use this URL as the `Authorization callback URL`, changing the port to your port: `http://localhost:8080/api/auth/callback/github`

![Creating the GitHub app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/89hx1kiy4qne1uwi07cm.PNG)

### Linking to the Database

We set up the Prisma connector so that Next-Auth would use Prisma functions to manage users in the database, so now we need to add required fields to the Prisma schema to create the tables in the database and the required Prisma functions. I added the models here to my Prisma schema: https://next-auth.js.org/adapters/prisma#setup. I also added the fields my project needed to the `User` model, like `projects` to connect the User to the projects they have access to.

Then I ran `npx prisma migrate dev --name "Added users to schema"` to update my database and generate the required prisma functions.

### Adding UI to Test the Functionality

Finally, we can add the basic Next Auth UI to actually test the authentication flow. I ran `npm run dev` to start the site and deleted all of the content on the homepage (`src/pages/index.tsx`). I copied the `pages/index.ts` file from the Next Auth "Example Code" section to get a basic auth flow setup with sign in and sign out buttons, and text to tell us our auth status.

I launched the site, and when I click sign-in, I get this view:
![Sign in to Github button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t52fqa03zxslmb3qo2cj.PNG)

...but the button didn't work! 🤯 I got a blue error message from Next Auth.

### Troubleshooting

In my server terminal, I got this error: 
```
https://next-auth.js.org/errors#oauth_callback_handler_error Error:
Invalid `prisma.account.findUnique()` invocation:

{
  where: {
    providerId_providerAccountId: {
      providerId: 'github',
      providerAccountId: 18769232
                         ~~~~~~~~
    }
  },
  select: {
    user: true
}

Argument providerAccountId: Got invalid value 18769232 on prisma.findUniqueAccount. Provided Int, expected String.
```
To fix this, in my schema I changed the type of `Account.providerAccountId` from `String` to `Int`, and a migration fixed this bug.

After relaunching, when I click the button.... it doesn't work again! I got redirected from `localhost:3000/...` to `localhost:8080/...` so I  fixed the problem by adding `NEXTAUTH_URL="http://localhost:8080/"` to my `.env`.

Finally, when I hit "Sign in with Github," I get to this:
![Sign in with GitHub](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w4ra51qksirx0pdqlqsa.PNG)

And after allowing access, I was redirected to my homepage, now signed in with the email linked to my GitHub account:

![Signed in](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1fgjv4sl899qdvh1q63e.PNG)

## Conclusion
In this update, I added authentication to my NextJS/Prisma/Postgres app with Next-Auth.

In the next update, I will create some API routes to implement the project's business logic, and get started on the UI.

*Follow me here or [on Twitter](https://twitter.com/ajones55555) for more updates and other content. Feel free to DM me for questions!*