Install NextAuth
yarn add next-auth
npm install next-auth
Version
"next": "14.1.4",
"next-auth": "^4.24.7"
Implementation
Let's start with Providers, For Google Login We need Google Provider (https://next-auth.js.org/providers/google)
import GoogleProvider from "next-auth/providers/google"; ... providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET }) ] ...
Now, How can we get our clientID anf clientSecrect?
Go to Google Cloud Console - console.developers.google.com/apis/credenti..
Create a New Project
Select Create crendentials and add a OAuth client ID
The "Authorized redirect URIs" used when creating the credentials must include your full domain and end in the callback path. For example;
For production:
https://{YOUR_DOMAIN}/api/auth/callback/google
For development:
http://localhost:3000/api/auth/callback/google
Form here you can access your ClientID and Client Secret
Put them is you .env
Now you can separate out your Auth Options in authOptions.ts file
//authOptions.ts import clientPromise from "@/lib/mongoClient"; import {AuthOptions} from "next-auth"; import GoogleProvider from "next-auth/providers/google"; export const authOptions:AuthOptions = { secret: process.env.AUTH_SECRET, providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID as string, clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, }), ], };
Now you need Adapter to store your users and sessions
Here we are using MongoDB to store out Users.(https://next-auth.js.org/adapters)
Add mongodb adapter
yarn add @auth/mongodb-adapter mongodb //or npm install @auth/mongodb-adapter mongodb
Setup:
Add MongoClient :
//mongoClient.ts import { MongoClient } from "mongodb"; if (!process.env.MONGODB_URI) { throw new Error("Please add your Mongo URI to .env.local"); } const uri: string = process.env.MONGODB_URI; let client: MongoClient; let clientPromise: Promise<MongoClient>; if (process.env.NODE_ENV === "development") { // In development mode, use a global variable so that the value // is preserved across module reloads caused by HMR (Hot Module Replacement). let globalWithMongoClientPromise = global as typeof globalThis & { _mongoClientPromise: Promise<MongoClient>; }; if (!globalWithMongoClientPromise._mongoClientPromise) { client = new MongoClient(uri); globalWithMongoClientPromise._mongoClientPromise = client.connect(); } clientPromise = globalWithMongoClientPromise._mongoClientPromise; } else { // In production mode, it's best to not use a global variable. client = new MongoClient(uri); clientPromise = client.connect(); } // Export a module-scoped MongoClient promise. By doing this in a // separate module, the client can be shared across functions. export default clientPromise;
Config Auth.js : use MongoDBAdapter (in Our case authOptions.js)
adapter: MongoDBAdapter(clientPromise)
Finally Auth.js File -
//authOptions.ts import clientPromise from "@/lib/mongoClient"; import {MongoDBAdapter} from "@auth/mongodb-adapter"; import {AuthOptions} from "next-auth"; import GoogleProvider from "next-auth/providers/google"; export const authOptions:AuthOptions = { secret: process.env.AUTH_SECRET, providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID as string, clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, }), ], // @ts-ignore adapter: MongoDBAdapter(clientPromise), };
Now Create a userClient.ts using authOptions
//userClient.ts import {authOptions} from "@/lib/authOptions"; import {getServerSession} from "next-auth"; export async function getUserEmail(): Promise<string> { const session = await getServerSession(authOptions); return session?.user?.email || ''; }
Now Create a API route for login in : api/auth/[...nextauth]
//route.ts import NextAuth from "next-auth" import { authOptions } from "@/lib/authOptions"; const handler = NextAuth(authOptions); export { handler as GET, handler as POST }
Let's Create a Login Page :
Just use the signIn('google') and BOOMMMM!!
'use client'; import { signIn } from "next-auth/react"; export default function LoginButton() { return ( <button onClick={() => signIn('google')} className="bg-gray-300 py-2 px-4 ml-2 rounded-md"> Login </button> ); }
Now to handle Logout:
We have magical singOut()
'use client'; import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; import { signOut } from "next-auth/react"; import {faArrowRightFromBracket} from "@fortawesome/free-solid-svg-icons"; export default function LogoutButton() { return ( <button onClick={() => signOut()} className="bg-gray-300 py-2 px-4 ml-2 rounded-md inline-flex gap-2 items-center"> Logout <FontAwesomeIcon icon={faArrowRightFromBracket} /> </button> ); }