Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 34 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,47 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
# Custom Authentication and Authorization Website

## Getting Started
Welcome to our website! This README file will guide you through the features and functionality of our custom authentication and authorization system.

First, run the development server:
## Overview

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Our website provides a custom authentication and authorization system to manage user access to different pages. It consists of two main pages:

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
1. **Public Page:** Accessible to all users, located at the root path (`/`).
2. **Private Page:** Accessible only to logged-in users, located at the `/private` path.

You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file.
Additionally, we have dedicated pages for signing up and logging in:

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
- **Signup Page:** Allows users to create a new account, located at `/sign-up`.
- **Login/Sign-in Page:** Enables existing users to log in to their accounts, located at `/sign-in`.

## Learn More
## Features

To learn more about Next.js, take a look at the following resources:
- **Custom Authentication:** We've implemented a custom authentication system to manage user logins securely.
- **Authorization:** Users can only access the private page (`/private`) if they are authenticated.
- **Error Handling:** If users provide invalid credentials during login, the server sends an error message to notify them.

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
## Usage

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
1. **Signup:** Visit the `/sign-up` page to create a new account. Provide necessary details such as username, email, and password.
2. **Login:** After signing up, visit the `/sign-in` page to log in with your credentials. If you're an existing user, enter your email and password.
3. **Access Private Page:** Once logged in, you can access the private page (`/private`) to view its content.

## Deploy on Vercel
## Technologies Used

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
- **Frontend:** Next JS
- **Backend:** Next JS server Action
- **Database:** MongoDB

Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
## Setup

1. Clone the repository to your local machine.
2. Install dependencies using [package manager]. For example, if using Node.js, run `npm install`.
3. Configure the backend server to connect to your database.
4. Run the server locally. Ensure that the necessary routes (public, private, signup, signin) are properly configured.
5. Access the website through your browser.

## Feedback

If you have any feedback or suggestions, please feel free to [contact us](mailto:[email protected]). We'd love to hear from you!

Thank you for using our custom authentication and authorization system. We hope you find it useful!
4 changes: 2 additions & 2 deletions actions/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use server";
import connectDB from "@/database/connectDb";
import User from "@/database/models/userModels";
import { generateJWTToken } from "@/utils";
import { encrypt, generateJWTToken } from "@/utils";
import bcrypt from "bcrypt";
import { cookies } from "next/headers";

Expand Down Expand Up @@ -69,7 +69,7 @@ export async function signIn(formData) {
}),
};
}
let token = await generateJWTToken(foundUser._id.toString());
let token = await encrypt({ user: foundUser._id.toString() });
cookies().set("token", token, { secure: true });
userOK = true;
return {
Expand Down
29 changes: 16 additions & 13 deletions app/access-decline/page.jsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import Navbar from "@/components/Navbar";
import SignInForm from "@/components/SignInForm";
import Link from "next/link";
import React from "react";

export default function page() {
return (
<div className="pt-32 flex justify-center items-center">
<div className="bg-white p-8 rounded-md shadow-md">
<h2 className="text-2xl font-bold mb-4">
Log in <span className="text-red-500"> for Access this page</span>
</h2>

<SignInForm />
<div className="mt-4 text-center">
<p>Don&rsquo;t have an account?</p>
<Link href="/sign-up" className="text-blue-500 hover:underline">
Sign Up
</Link>
<>
<Navbar />
<div className="pt-32 flex justify-center items-center">
<div className="bg-white p-8 rounded-md shadow-md">
<h2 className="text-2xl font-bold mb-4">
Log in <span className="text-red-500"> for Access this page</span>
</h2>
<SignInForm />
<div className="mt-4 text-center">
<p>Don&rsquo;t have an account?</p>
<Link href="/sign-up" className="text-blue-500 hover:underline">
Sign Up
</Link>
</div>
</div>
</div>
</div>
</>
);
}
5 changes: 1 addition & 4 deletions app/layout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ export const metadata = {
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className + " relative"}>
<Navbar />
{children}
</body>
<body className={inter.className + " relative"}>{children}</body>
</html>
);
}
2 changes: 0 additions & 2 deletions app/loading.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import React from "react";

export default function loading() {
return (
<div
Expand Down
3 changes: 2 additions & 1 deletion app/page.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import Navbar from "@/components/Navbar";
import Image from "next/image";
import publicImage from "@/public/Public.gif";
import publicImage from "@/public/public.gif";

export default function Home() {
return (
<div className="h-screen">
<Navbar />
<div className="flex justify-center -mt-16 h-full items-center ">
<div className="text-center flex flex-col items-center">
<Image src={publicImage} alt="Public Icon" />
Expand Down
1 change: 1 addition & 0 deletions app/private/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import privateImage from "@/public/private.gif";
export default function Home() {
return (
<div className="h-screen">
<Navbar />
<div className="flex justify-center -mt-16 h-full items-center ">
<div className="text-center flex flex-col items-center">
<Image src={privateImage} alt="private Icon" />
Expand Down
11 changes: 6 additions & 5 deletions components/LogoutButton.jsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
"use client";

import { signOut } from "@/actions";
import { useEffect } from "react";
import { useState } from "react";

export default function LogoutButton() {
useEffect(() => {
console.log("run once");
});
const [loading, setLoading] = useState(false);
if (loading) return <p className="text-white">Loading...</p>;
return (
<button
onClick={async () => {
setLoading(true);
let res = await signOut();
if (res.response) {
window.location.reload();
}
setLoading(false);
}}
href="logout"
className="bg-red-600 rounded p-2 text-white hover:text-gray-300"
className=" rounded p-2 text-white hover:text-gray-300"
>
Log out
</button>
Expand Down
2 changes: 0 additions & 2 deletions components/NavLogoutButtonArea.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { cookies } from "next/headers";
import Link from "next/link";
import LogoutButton from "./LogoutButton";
import { redirect } from "next/navigation";
export default function NavLogoutButtonArea() {
const login = cookies().get("token");

return (
<li>
{login ? (
Expand Down
3 changes: 0 additions & 3 deletions components/Navbar.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { navItems } from "@/constant";
import { cookies } from "next/headers";
import Link from "next/link";
import React from "react";
import LogoutButton from "./NavLogoutButtonArea";
import NavLogoutButtonArea from "./NavLogoutButtonArea";

const Navbar = () => {
Expand Down
25 changes: 12 additions & 13 deletions middleware.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import { NextResponse } from "next/server";
import { verifyJWT } from "./utils";
import { decrypt } from "./utils";

export async function middleware(req) {
console.log("middleware running");
const url = req.nextUrl.clone();
const token = req.cookies.get("token");
// if (!token) {
// const url = req.nextUrl.clone();
// url.pathname = "/access-decline";
// return NextResponse.rewrite(url);
// }
// let decoded = await verifyJWT(token.value);
// console.log(decoded);
// const url = req.nextUrl.clone();
// url.pathname = "/private";
// return NextResponse.rewrite(url);
if (!token) {
url.pathname = "/access-decline";
return NextResponse.rewrite(url);
}
let decoded = await decrypt(token.value);
if (!decoded) {
url.pathname = "/access-decline";
return NextResponse.rewrite(url);
}
}
export const config = {
matcher: ["/private", "/sign-in", "/sign-up"],
matcher: ["/private"],
};
36 changes: 24 additions & 12 deletions utils/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import jose from "jose";
export const generateJWTToken = async (payload) => {
const alg = "HS256";
const jwt = await new jose.SignJWT(payload)
.setProtectedHeader({ alg })
import { SignJWT, jwtVerify } from "jose";

const secretKey = "secret";
const key = new TextEncoder().encode(secretKey);

export async function encrypt(payload) {
const expirationTime = new Date();
expirationTime.setHours(expirationTime.getHours() + 1);
return await new SignJWT(payload)
.setProtectedHeader({ alg: "HS256" })
.setIssuedAt()
.setIssuer("urn:example:issuer")
.setAudience("urn:example:audience")
.setExpirationTime("2h")
.sign(process.env.JWT_SECRET);
console.log(jwt);
return jwt;
};
.setExpirationTime(expirationTime)
.sign(key);
}

export async function decrypt(input) {
try {
const { payload } = await jwtVerify(input, key, {
algorithms: ["HS256"],
});
return payload;
} catch (error) {
return false;
}
}