Blog

My Journey as a Web Developer

Easy Authentication using Next-Auth

05/03/2023

author avatar

Authentication is an essential part of web development. It is how we verify that a user is who they say they are and give them access to the appropriate resources. However, implementing authentication can be a challenging task, especially when it comes to security. Fortunately, Next-Auth provides a simple and secure solution for authentication in Next.js applications. In this post, we will explore how to use Next-Auth with GoogleProvider and email magic links and discuss why passwords are no longer a secure way of authentication.

Why We Shouldn't Use Passwords Anymore

Passwords are no longer considered a secure way of authentication due to the number of data breaches that have exposed users' passwords. Passwords are often reused across multiple services and are susceptible to dictionary and brute force attacks. Furthermore, users often choose weak passwords that can be easily guessed by attackers. A better way to authenticate users is to use stronger and more secure methods such as two-factor authentication (2FA) and magic links.

Using Next-Auth with GoogleProvider

Next-Auth provides support for various authentication providers such as GoogleProvider, Facebook, GitHub, Twitter, and more. Here's an example of how to use GoogleProvider with Next-Auth in your Next.js application.

  1. Install next-auth.
npm install next-auth
  1. Create a route handler with the app directory. You should be using that by now. Inside it, we will declare our provider in the authOptions. We will get our clientId and secret later on, but we will declare them now.
/app/api/auth/[...nextauth]/route.ts

export const authOptions = {
  providers : [
    GoogleProvider({
    clientId: process.env.GOOGLE_CLIENT_ID,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET
  })
],
pages: {
  signIn: '/login'
}
}

const handler = NextAuth(authOptions)

export { handler as GET, handler as POST }
  1. Now we need to create the login page. This, I am sure, you can design yourself, but the important part is the login button.
import { signIn } from 'next-auth/react'

 <Button
      className='w-full'
      onClick={() => signIn('google')}
    >
      Continue with Google
    </Button>

So simple, right?

  1. Well you're still missing your clientId and secret, so don't try it just yet. Here's how to get them.

*https://console.developers.google.com/apis/credentials *

You click the link above to go into your google developer console.

Create your project. google-oauth-1

Name it and hit create. google-0auth-2

Now at the top, click '+ create credentials' and then 0auth client id. google-0auth-3

The last step in Google is to add an authorized redirect URL. This will have to change when in production to your domain. google-0auth-4

Insert those into your .env file and you are almost there.

  1. Your authentication implementation is close. Users have access to the functionality of a login system, but it won't work just yet until it's hooked up with a database. It can work without one if it's for internal tools, but for a consumer facing application, you'll need to persist those accounts in a database. For this, we will use MongoDB. I'll assume you know to set up a free MongoDB cluster. If not, there are many many tutorials showing how to do this.

  2. We will now interact with that database and we will use Prisma as our ORM. I love the ease of Prisma, it's so intuitive. We will need the following 3 packages.

npm install @prisma/client @next-auth/prisma-adapter
npm install prisma --save-dev

Let's go ahead and create a folder and file as below.

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}

model Account {
  id String @id @default(auto()) @map("_id") @db.ObjectId
  userId             String   @db.ObjectId
  type               String
  provider           String
  providerAccountId  String
  refresh_token      String?  @db.String
  access_token       String?  @db.String
  expires_at         Int?
  token_type         String?
  scope              String?
  id_token           String?  @db.String
  session_state      String?
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
  @@unique([provider, providerAccountId])
}

model Session {
  id String @id @default(auto()) @map("_id") @db.ObjectId
  sessionToken String @unique
  userId String @db.ObjectId
  expires DateTime
 user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}

model User {
  id String @id @default(auto()) @map("_id") @db.ObjectId
  email String @unique
  emailVerified DateTime?
  name String?
  image String?
  accounts Account[]
  sessions Session[]
}

model VerificationToken {
  id String @id @default(auto()) @map("_id") @db.ObjectId
  identifier String   
  token      String   @unique
  expires    DateTime

  @@unique([identifier, token])
}

This is everything you need to connect users, sessions and accounts for the schema. You will need to grab your database url from MongoDB and add it to your .env file.

  1. Next, we'll add a file to our lib folder, assuming you have one, and we'll call it db.jsx/tsx/js.ts whichever you are working. This file just deals with Next.js hot reloading to ensure we don't create a lot of prisma clients.
import { PrismaClient } from "@prisma/client"

let prisma
if (process.env.NODE_ENV === "production") {
  prisma = new PrismaClient()
} else {
  if (!global.cachedPrisma) {
    global.cachedPrisma = new PrismaClient()
  }
  prisma = global.cachedPrisma
}

export const db = prisma
  1. Our schema is set up and now all we have to do is push our schema to Prisma.
npx prisma db push

We are done. Congratulations, you have authentication in Next.js

← Blog Home