# Implementing Google Login in NextJS 14: A Complete Guide with AuthJS 5, MongoDB, and Prisma ORM

### Introduction

In today’s digital landscape, secure user authentication is crucial for any web application. Google authentication provides a seamless and secure way for users to log in using their Google accounts. This tutorial will guide you through implementing Google authentication in a NextJS 14 application using AuthJS 5, MongoDB, and Prisma ORM.

By the end of this article, you’ll have a robust authentication system that leverages the power of modern web technologies, ensuring both security and ease of use.

Let’s dive in and get started with setting up our NextJS project!

---

### Setting Up the Project

**1\. Initialize a NextJS Project**

First, we’ll create a new NextJS project named `nextjs-google-auth` by running the following command:

```bash
npx create-next-app@latest nextjs-google-auth
```

Follow the prompts to set up the project according to your preferences.

**2\. Navigate to the Project Directory**

Move into the newly created project directory:

```bash
cd nextjs-google-auth
```

3\. Install Necessary Dependencies  
Next, install the required packages for authentication and database management:

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

> **Note:** We use `next-auth@beta` because Auth.js version 5 is currently in beta. If you're reading this in the future when Auth.js 5 is fully released, you can install it with `npm install next-auth` .

**4\. Set Up Google Auth Credentials**  
We will need a Google Auth Client ID and Client Secret. To generate these credentials:

* Go to the [Google Cloud Console](https://console.developers.google.com/apis/credentials)
    
* Register a new application and create OAuth 2.0 credentials.
    
* Set the Callback URL to: `https://<your-site>/api/auth/callback/google` .
    

Copy the generated Client ID and Client Secret, and paste them into the `.env` file in your project directory:

```plaintext
AUTH_GOOGLE_ID="your-google-client-id"
AUTH_GOOGLE_SECRET="your-google-client-secret"
```

**5\. Generate an Auth Secret**  
Run the following command to generate a secret for authentication and add it to the `.env` file:

```bash
npx auth secret
```

Add the generated secret to your `.env` file:

```plaintext
AUTH_SECRET="your-auth-secret"
```

**6\. Set Up the Database**

Go to the [MongoDB website](https://www.mongodb.com/) and create a new database. Once the database is created, obtain the connection string.

Remember to include your database name in the connection string. Add this connection string to your `.env` file:

```plaintext
DATABASE_URL="mongodb+srv://<username>:<password>@<cluster-url>/<your-db-name>?retryWrites=true&w=majority&appName=<app-name>"
```

This sets up the basic configuration for your project, ensuring you have the necessary environment variables and dependencies to proceed with implementing Google authentication.

Next, we will configure Prisma to work with MongoDB.

---

### Configuring Prisma ORM

**1\. Initialize Prisma**  
Run the following command to initialize Prisma with MongoDB as the datasource provider:

```bash
npx prisma init --datasource-provider mongodb
```

This will generate a `prisma` folder and a `schema.prisma` file inside it.

**2\. Configure the Prisma Schema**  
Replace the contents of the `prisma/schema.prisma` file with the following:

```plaintext
// prisma/schema.prisma

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

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

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

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?
  createdAt         DateTime @default(now())
  updatedAt         DateTime @updatedAt
  user              User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([provider, providerAccountId])
}
```

**3\. Generate Prisma Client**  
Run the following command to generate the Prisma client based on the updated schema:

```bash
npx prisma generate
```

This configures Prisma to work with MongoDB and sets up the necessary models for handling user authentication data.

---

### Configuring the Database Connection and Authentication

**1\. Create a**`lib`**Folder**  
Inside the `src` folder, create a `lib` folder to store our database and authentication configurations.

**2\. Create**`db.ts`**in the**`lib`**Folder**  
Create a `db.ts` file inside the `lib` folder with the following content:

```typescript
// @/lib/db.ts

import { PrismaClient } from "@prisma/client";

const prismaClientSingleton = () => {
  return new PrismaClient();
};

declare global {
  var prisma: undefined | ReturnType<typeof prismaClientSingleton>;
}

const db = globalThis.prisma ?? prismaClientSingleton();

export default db;

if (process.env.NODE_ENV !== "production") globalThis.prisma = db;
```

**3\. Create**`auth.config.ts`**in the**`lib`**Folder**  
Create a `auth.config.ts`file inside the `lib` folder with the following content:

```typescript
// @/lib/auth.config.ts

import { NextAuthConfig } from "next-auth";
import Google from "next-auth/providers/google";

export const authConfig: NextAuthConfig = {
  providers: [Google],
};
```

**4\. Create**`auth.ts`**in the**`src`**Folder**  
Create a `auth.ts` file inside the `src` folder with the following content:

```typescript
// @/auth.ts

import NextAuth from "next-auth";
import { authConfig } from "@/lib/auth.config";
import { PrismaAdapter } from "@auth/prisma-adapter";
import db from "@/lib/db";

export const { handlers, signIn, signOut, auth } = NextAuth({
 ...authConfig,
 adapter: PrismaAdapter(db),
 session: {
  strategy: "jwt",
 },
 pages: {
  signIn: "/login",
 },
 callbacks: {
  async jwt({ token, user }) {
   if (user) {
    // get user from db with the email
    // if there is no user with the email, create new user
    // else set the user data to token
   }

   return token;
  },

  async session({ session, token }) {
   if (token) {
    // set the token data to session
   }

   return session;
  },

  redirect() {
   return "/login";
  },
 },
});
```

---

### **Setting Up API Routes and Middleware**

**1\. Create API Route for Authentication**  
Inside the `app` folder, create an `api` folder, then an `auth` folder, and finally a `[...nextauth]` folder inside it. Create a `route.ts` file inside the `[...nextauth]` folder with the following content:

```typescript
// @/app/api/auth/[…nextauth]/route.ts

import { handlers } from "@/auth";

export const { GET, POST } = handlers;
```

**2\. Create**`routes.ts`**in the**`src`**Folder**  
Create a `routes.ts` file inside the `src` folder with the following content:

```typescript
// @/routes.ts

export const API_AUTH_PREFIX = "/api/auth";

export const AUTH_ROUTES = ["/login"];

export const PROTECTED_ROUTES = [
  "/",
  // your other protected routes
]
```

**3\. Create**`middleware.ts`**in the**`src`**Folder**Create a `middleware.ts` file inside the `src` folder with the following content:

```typescript
// @/middleware.ts

import NextAuth from "next-auth";
import { NextResponse } from "next/server";

import { authConfig } from "@/lib/auth.config";
import { API_AUTH_PREFIX, AUTH_ROUTES, PROTECTED_ROUTES } from "@/routes";

export const { auth } = NextAuth(authConfig);

export default auth(req => {
 const pathname = req.nextUrl.pathname;

 // manage route protection
 const isAuth = req.auth;

 const isAccessingApiAuthRoute = pathname.startsWith(API_AUTH_PREFIX);
 const isAccessingAuthRoute = AUTH_ROUTES.some(route => pathname.startsWith(route));
 const isAccessingProtectedRoute = PROTECTED_ROUTES.some(route => pathname.startsWith(route));

 if (isAccessingApiAuthRoute) {
  return NextResponse.next();
 }

 if (isAccessingAuthRoute) {
  if (isAuth) {
   return NextResponse.redirect(new URL("/", req.url));
  }

  return NextResponse.next();
 }

 if (!isAuth && isAccessingProtectedRoute) {
  return NextResponse.redirect(new URL("/login", req.url));
 }
});

export const config = {
 matcher: ["/((?!.+\\.[\\w]+$|_next).*)", "/", "/(api|trpc)(.*)"],
};
```

This setup configures the database connection, authentication system, API routes, and middleware for your NextJS application.

---

### Implementing Authentication Pages

**1\. Create the Login Page**  
Inside the `app` folder, create a `login` folder. Inside the `login` folder, create a `page.tsx` file with the following content:

```typescript
// @/app/login/page.tsx

import { signIn } from "@/auth";

const LoginPage = () => {
 return (
   <form
     action={async () => {
       "use server";
       await signIn("google");
     }}
   >
     <button type="submit">Login with Google</button>
   </form>
   );
};

export default LoginPage;
```

**2\. Create the Home Page**  
Inside the `app` folder, create a `page.tsx` file with the following content:

```typescript
// @/app/page.tsx

import { auth, signOut } from "@/auth";
import { notFound } from "next/navigation";

const HomePage = async () => {
 const session = await auth();
 if (!session) return notFound();
 return (
   <main>
     <h1>Hello {session.user.name}</h1>

     <form
       action={async () => {
         "use server";
         await signOut();
       }}
     >
       <button type="submit">Log Out</button>
     </form>
   </main>
 );
};
export default HomePage;
```

**3\. Run the Development Server**  
Run the following command in your terminal:

```bash
npm run dev
```

If everything is set up correctly, you will be asked to log in with your Google account. Once logged in, you should be able to see the home page with a greeting and an option to log out.

---

### Conclusion

Implementing Google authentication in a Next.js 14 application using NextAuth.js 5 (beta), Prisma ORM, and MongoDB can be a streamlined and efficient process. By following the steps outlined in this article, you can set up a robust authentication system that leverages Google’s OAuth 2.0 for user authentication, Prisma for database management, and MongoDB as the database.

Here’s a brief recap of what we covered:

1. **Project Setup**: Initializing a Next.js project and installing necessary dependencies.
    
2. **Google Auth Credentials**: Configuring Google OAuth 2.0 credentials.
    
3. **Database Setup**: Setting up a MongoDB database and configuring Prisma ORM.
    
4. **Prisma Configuration**: Initializing Prisma and defining schema models for `User` and `Account`.
    
5. **Authentication Configuration**: Setting up NextAuth.js configuration with Prisma adapter and custom callbacks.
    
6. **API Routes and Middleware**: Defining API routes for authentication and implementing middleware for route protection.
    
7. **Authentication Pages**: Creating login and home pages with server actions for sign-in and sign-out.
    

With this setup, you now have a fully functional authentication system integrated into your Next.js application. This foundation can be further extended to include more features such as authorization, role-based access control, and additional OAuth providers.

Feel free to customize and expand upon this setup to fit the specific needs of your application. For a complete reference and code implementation, you can visit the [GitHub Repository](https://github.com/SSazzadur/nextjs-google-auth).

Happy coding!

---

### GitHub Repository

%[https://github.com/SSazzadur/nextjs-google-auth]
