Project Description
Step 1: First Install following npm packages by running below command
npm install axios bcrypt mongoose next-auth
Step 2: Update next.config.mjs file
- Add Mongo DB URL By using Mongo DB Compass and copy and paste your connection string
and rest of parameters you can keep as example provided below
/** @type {import('next').NextConfig} */const nextConfig = { env: { NEXT_PUBLIC_HOSTNAME: "http://localhost:3000/api/", MONGODB_URI: "mongodb://localhost:27017/codingmstr", NEXTAUTH_SECRET: "codingmstrsecret", NEXTAUTH_URL: "http://localhost:3000", SECRET: "RAMDOM_STRING", },};
export default nextConfig;
/** @type {import('next').NextConfig} */
const nextConfig = {
env: {
NEXT_PUBLIC_HOSTNAME: "http://localhost:3000/api/",
MONGODB_URI: "mongodb://localhost:27017/codingmstr",
NEXTAUTH_SECRET: "codingmstrsecret",
NEXTAUTH_URL: "http://localhost:3000",
SECRET: "RAMDOM_STRING",
},
};
export default nextConfig;
Step 3: Create NextAuth Files
Go to 'src\app\api\auth\[...nextauth]' and createoptions.tsroute.ts
Step 4: Update options.ts
Go to 'src\app\api\auth\[...nextauth]' and create
options.ts
route.ts
Step 4: Update options.ts
Step 4: Update options.ts
//@ts-nocheck
import type { NextAuthOptions } from "next-auth";
import GitHubProvider from "next-auth/providers/github";
import CredentialsProvider from "next-auth/providers/credentials";
import GoogleProvider from "next-auth/providers/google";
const baseURL = process.env.NEXT_PUBLIC_HOSTNAME + "login";
export const options: NextAuthOptions = {
session: {
strategy: "jwt",
},
providers: [
GitHubProvider({
clientId: process.env.GITHUB_ID as string,
clientSecret: process.env.GITHUB_SECRET as string,
}),
GoogleProvider({
clientId: process.env.NEXT_GOOGLE_CLIENT_ID as string,
clientSecret: process.env.NEXT_GOOGLE_CLIENT_SECRET as string,
}),
CredentialsProvider({
name: "Credentials",
credentials: {
username: { label: "Email", type: "email", placeholder: "" },
password: { label: "Password", type: "password" },
},
async authorize(credentials, req) {
// This is where you need to retrieve user data
// to verify with credentials
// Docs: https://next-auth.js.org/configuration/providers/credentials
const requestBody = {
email: credentials.email,
password: credentials.password,
};
const res = await fetch(baseURL, {
method: "POST",
body: JSON.stringify(requestBody),
headers: { "Content-Type": "application/json" },
});
const resdata = await res.json();
console.log("Login...", resdata);
if (
resdata.status === 400 ||
resdata.status === 401 ||
resdata.status === 403 ||
resdata.status === 500
) {
return null;
}
if (resdata.status === 200 || resdata.status === 201) {
return resdata;
}
// Return null if user data could not be retrieved
return null;
},
}),
],
pages: {
// signIn: "/",
// error: '/auth/error',
// signOut: '/auth/signout'
},
callbacks: {
async jwt({ token, user }) {
// the user present here gets the same data as received
// from DB call made above -> fetchUserInfo(credentials.opt)
return { ...token, ...user };
},
async session({ session, user, token }) {
// user param present in the session(function) does not recive
//all the data from DB call -> fetchUserInfo(credentials.opt)
return token;
},
},
secret: process.env.JWT_SECRET,
};
Step 5: Update route.ts File
import NextAuth from 'next-auth'import { options } from './options'
const handler = NextAuth(options)
export { handler as GET, handler as POST }
import NextAuth from 'next-auth'
import { options } from './options'
const handler = NextAuth(options)
export { handler as GET, handler as POST }
Step 6. Go to 'src\app\context\authrovider.tsx' and create
authprovider.tsx source code
"use client";
import { SessionProvider } from "next-auth/react";
export default function AuthProvider({
children,
}: {
children: React.ReactNode;
}) {
return <SessionProvider>{children}</SessionProvider>;
}
Step 7. Use AuthProvider and Update root layout.tsx file
- Path of layout.jsx file is ''src\app\layout.tsx''
- Path of layout.jsx file is ''src\app\layout.tsx''
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import AuthProvider from "./context/authprovider";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={inter.className}>
<AuthProvider>{children}</AuthProvider>
</body>
</html>
);
}
NOW WE WILL SET THE DATABASE
Step 8: Create dbConnect.js file at 'src\db\config\dbConnect.js' directory
import mongoose from "mongoose";
const MONGODB_URI = process.env.MONGODB_URI;
if (!MONGODB_URI) {
throw new Error(
'Please define Mongo DB URI'
)
}
let cached = global.mongoose
if (!cached) {
cached = global.mongoose = { conn: null, promise: null }
}
async function dbConnect() {
if (cached.conn) {
return cached.conn
}
if (!cached.promise) {
const opts = {
bufferCommands: true,
}
cached.promise = await mongoose.connect(MONGODB_URI, opts).then((mongoose) => {
return mongoose
})
}
try {
cached.conn = await cached.promise
} catch (e) {
cached.promise = null
throw e
}
return cached.conn
}
export default dbConnect
Step 9: Create USER MODEL file 'user.js' at 'src\db\models\user.js' directory
import mongoose from 'mongoose';
const { Schema } = mongoose;
const userSchema = new Schema({
name: String,
email: String,
password: String
});
export default mongoose.models.User || mongoose.model('User', userSchema);
Step 10: Create LOGIN API file 'route.js' at 'src\app\api\login\route.js' directory
import dbConnect from "@/db/config/dbConnect";
import User from "@/db/models/user";
import bcrypt from 'bcrypt';
dbConnect();
export async function GET(request) {
const users = await User.find({}).sort({ _id: -1 });
let data = JSON.stringify(users);
return new Response(data, {
status: 200,
});
}
export async function POST(request) {
const { email, password } = await request.json();
// Check if email and password are provided
if (!email || !password) {
return new Response(JSON.stringify({
success: false,
status: 400,
message: 'email and password are required',
data: email,
}));
}
// Find the user in the database
const user = await User.findOne({ email });
// If user is not found, return an error
if (!user) {
return new Response(JSON.stringify({
success: false,
status: 400,
message: 'Invalid credentials'
}));
}
// if(password == user.password) {
// return new Response(JSON.stringify({
// success: true,
// status: 200,
// data: user
// }));
// }else{
// return new Response(JSON.stringify({
// success: false,
// status: 400,
// message: 'Wrong Password'
// }));
// }
const isPasswordValid = await bcrypt.compare(password, user.password);
if (isPasswordValid) {
return new Response(JSON.stringify({
success: true,
status: 200,
data: user
}));
} else {
return new Response(JSON.stringify({
success: false,
status: 400,
message: 'Wrong Password'
}));
}
}
Step 11: Create REGISTER API file 'route.js' at 'src\app\api\register\route.js' directory
import dbConnect from "@/db/config/dbConnect";
import User from "@/db/models/user";
import bcrypt from 'bcrypt';
dbConnect();
export async function POST(request) {
const { email, password } = await request.json();
const existingUser = await User.findOne({ email });
if (existingUser) {
return new Response(data, {
message: 'Email is already taken',
status: 400,
});
}
// Hash the password before storing it in the database
const hashedPassword = await bcrypt.hash(password, 10);
console.log('Data ', email, ' ', password, ' ', hashedPassword);
// If user is created successfully, return a success message
const users = await User.create({ email, password: hashedPassword });
let data = JSON.stringify(users);
console.log('users ', users);
return new Response(data, {
status: 200,
});
}
Step 12: Create Login Page
"use client";import React from "react";import { signIn } from "next-auth/react";import { useRouter } from 'next/navigation';
const Login = () => { const router = useRouter();
const submitHandler = async (data) => { const resdata = await signIn("credentials", { email: data.email, password: data.password, redirect: false, });
console.log(resdata); if ( resdata.status === 400 || resdata.status === 401 || resdata.status === 403 ) { console.log("Invalid Credentials!"); alert('Invalid Credentials!'); } else if (resdata.status === 500) { console.log( "Server error!" ); alert('Server error!'); } else { alert('Login successfull!'); router.push('/home'); console.log(resdata); } };
return ( <div className="min-h-screen flex items-center justify-center bg-gray-50"> <div className="max-w-md w-full p-6 bg-white rounded-md shadow-md"> <h2 className="text-2xl font-bold mb-4">Login</h2> <form onSubmit={(e) => { e.preventDefault(); submitHandler({ email: e.target.username.value, password: e.target.password.value, }); }}> <div className="mb-4"> <label htmlFor="username" className="block text-sm font-medium text-gray-600" > Username </label> <input type="text" id="username" name="username" className="mt-1 p-2 w-full border rounded-md" /> </div> <div className="mb-4"> <label htmlFor="password" className="block text-sm font-medium text-gray-600" > Password </label> <input type="password" id="password" name="password" className="mt-1 p-2 w-full border rounded-md" /> </div> <button type="submit" className="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600" > Login </button> </form> </div> </div> );};
export default Login;
"use client";
import React from "react";
import { signIn } from "next-auth/react";
import { useRouter } from 'next/navigation';
const Login = () => {
const router = useRouter();
const submitHandler = async (data) => {
const resdata = await signIn("credentials", {
email: data.email,
password: data.password,
redirect: false,
});
console.log(resdata);
if (
resdata.status === 400 ||
resdata.status === 401 ||
resdata.status === 403
) {
console.log("Invalid Credentials!");
alert('Invalid Credentials!');
} else if (resdata.status === 500) {
console.log(
"Server error!"
);
alert('Server error!');
} else {
alert('Login successfull!');
router.push('/home');
console.log(resdata);
}
};
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50">
<div className="max-w-md w-full p-6 bg-white rounded-md shadow-md">
<h2 className="text-2xl font-bold mb-4">Login</h2>
<form onSubmit={(e) => {
e.preventDefault();
submitHandler({
email: e.target.username.value,
password: e.target.password.value,
});
}}>
<div className="mb-4">
<label
htmlFor="username"
className="block text-sm font-medium text-gray-600"
>
Username
</label>
<input
type="text"
id="username"
name="username"
className="mt-1 p-2 w-full border rounded-md"
/>
</div>
<div className="mb-4">
<label
htmlFor="password"
className="block text-sm font-medium text-gray-600"
>
Password
</label>
<input
type="password"
id="password"
name="password"
className="mt-1 p-2 w-full border rounded-md"
/>
</div>
<button
type="submit"
className="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600"
>
Login
</button>
</form>
</div>
</div>
);
};
export default Login;
Step 13: Create Sign Up Page
"use client";
import React from "react";
import { useRouter } from 'next/navigation';
import axios from 'axios';
const Login = () => {
const router = useRouter();
const baseURL = process.env.NEXT_PUBLIC_HOSTNAME + "register";
const submitHandler = async (data) => {
const requestBody = {
email: data.email,
password: data.password
}
await axios
.post(baseURL, requestBody)
.then(function (res) {
console.log(res);
alert('Account created!');
router.push('/');
})
.catch(function (error) {
alert('Something went wrong...');
});
};
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50">
<div className="max-w-md w-full p-6 bg-white rounded-md shadow-md">
<h2 className="text-2xl font-bold mb-4">Register</h2>
<form onSubmit={(e) => {
e.preventDefault();
submitHandler({
email: e.target.username.value,
password: e.target.password.value,
});
}}>
<div className="mb-4">
<label
htmlFor="username"
className="block text-sm font-medium text-gray-600"
>
Username
</label>
<input
type="text"
id="username"
name="username"
className="mt-1 p-2 w-full border rounded-md"
/>
</div>
<div className="mb-4">
<label
htmlFor="password"
className="block text-sm font-medium text-gray-600"
>
Password
</label>
<input
type="password"
id="password"
name="password"
className="mt-1 p-2 w-full border rounded-md"
/>
</div>
<button
type="submit"
className="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600"
>
Sign up
</button>
</form>
</div>
</div>
);
};
export default Login;

