Create Your First Authentication System with Prisma, MongoDB, and NextAuth
Creating a login system can be complex and take a lot of time. But NextAuth makes it much easier!
Getting Started
Initializing the Project
- Initialize your project with
create-next-app
:
yarn create next-app website --eslint --tailwind --app --use-yarn --ts website
This command sets up a new Next.js project with all the essential tools for building a modern web app, including ESLint for code quality, Tailwind CSS for styling, and TypeScript for type safety.
Installing Dependencies
- Install the core packages for authentication:
yarn add next-auth @auth/prisma-adapter @prisma/client
next-auth
provides the core authentication functionality.@auth/prisma-adapter
bridges the gap between NextAuth and Prisma for seamless database interactions.@prisma/client
enables you to interact with your MongoDB database using Prisma’s powerful ORM.
- Install Prisma as a development dependency:
yarn add -D prisma
Initalizing Prisma
- Initialize Prisma
yarn prisma init --datasource-provider mongodb
- Add your data to the following config to
.env
DATABASE_URL="mongodb://localhost:27017/yourdb"
NEXT_PUBLIC_GOOGLE_CLIENT_ID="...."
NEXT_PUBLIC_GOOGLE_CLIENT_SECRET="...."
- Create Model Schema
prisma/schema.prisma
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
name String?
email String? @unique
emailVerified DateTime?
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])
}
- Push to Database
yarn prisma db push
- Create
prisma.ts
inlib
in the root of the project
lib/prisma.ts
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
export default prisma
Coding
- This component utilizes NextAuth’s SessionProvider to make the session object accessible throughout your app. Here’s an example
components/Providers.tsx
"use client"
import { type Session, SessionProvider } from 'next-auth/react';
import * as React from 'react';
export default function Providers({ children, session } : { children : React.ReactNode, session: Session | null }) {
return (
<SessionProvider>
{children}
</SessionProvider>
)
}
- Add Provider to the layout.
app/layout.tsx
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import './globals.css'
import Providers from '@/components/Providers'
import { getServerSession } from "next-auth"
const inter = Inter({ subsets: ['latin'] })
export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}
export default async function RootLayout({
children,
}: {
children: React.ReactNode
}) {
const session = await getServerSession()
return (
<html lang="en">
<body className={inter.className}>
<Providers session={session}>
{children}
</Providers>
</body>
</html>
)
}
Creating Authentication System
- Create
authOptions.ts
inapp/api/auth/[...nextauth]/authOptions.ts
This file configures NextAuth. Here’s an example
app/api/auth/[...nextauth]/authOptions.ts
import { type AuthOptions } from "next-auth";
import GoogleProvider from "next-auth/providers/google";
import { PrismaAdapter } from '@auth/prisma-adapter';
import prisma from "@/lib/prisma";
const authOptions: AuthOptions = {
adapter: PrismaAdapter(prisma),
providers: [
GoogleProvider({
clientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID,
clientSecret: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_SECRET
})
],
debug: process.env.NODE_ENV == "development" ? true : false
}
export default authOptions;
- Create
authOptions.ts
inapp/api/auth/[...nextauth]/
This file defines the NextAuth API route handler. Here’s an example
app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth/next";
import authOptions from './authOptions.ts'
const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }
Configure routes and protected content
- Create
middleware.ts
in root of the project (You can use regex)
middleware.ts
export { default } from "next-auth/middleware"
export const config = { matcher: ["/protected"] }
Deploying
Deploying the project need some configuration
- Configure Your
package.json
package.json
{
...
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"postinstall": "prisma generate"
},
...
}
Congratulations! You’ve successfully set up an authentication system using NextAuth, Prisma, and MongoDB for your Next.js project. This system provides a secure and efficient way to manage user authentication and sessions.
Happy Coding🥳