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 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. 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.
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:
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
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:
...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:
And after allowing access, I was redirected to my homepage, now signed in with the email linked to my GitHub account:
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 for more updates and other content. Feel free to DM me for questions!
Top comments (1)
You might want to take a look at -doppler.com/
Its awesome & we are already planning to use it.