diff --git a/.env.example b/.env.example
index fb1c90de..b33c2557 100644
--- a/.env.example
+++ b/.env.example
@@ -1,3 +1,4 @@
+BASE_URL=http://localhost:3000
 #
 # Database 
 #
@@ -14,8 +15,19 @@ CDN_API_KEY=api-key
 CDN_BASE_UPLOAD_URL=https://sg.storage.bunnycdn.com/job-board/assets
 CDN_BASE_ACCESS_URL=https://job-board.b-cdn.net/assets
 
-
 NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=maps-api-key
 
+# 
+# Email SMTP credentials
+# 
+EMAIL_USER=user@gmail.com
+EMAIL_PASSWORD=
+
+# 
+# Google OAuth credentials
+# 
+GOOGLE_CLIENT_ID=
+GOOGLE_CLIENT_SECRET=
+
 # To run the application in production environment / check the envs 
 # SKIP_ENV_CHECK=true npm run [replace with your script name]
diff --git a/README.md b/README.md
index a13d9175..d64fa79f 100644
--- a/README.md
+++ b/README.md
@@ -48,15 +48,27 @@ Follow these steps to set up the repository locally and run it.
    #
    NEXTAUTH_SECRET=
    NEXTAUTH_URL="http://localhost:3000"
-   
+
    #
    # Bunny CDN
    #
    CDN_API_KEY=
    CDN_BASE_UPLOAD_URL=
    CDN_BASE_ACCESS_URL=
-   
+
    NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=
+
+   #
+   # Email SMTP credentials
+   #
+   EMAIL_USER=user@gmail.com
+   EMAIL_PASSWORD=
+
+   #
+   # Google OAuth credentials
+   #
+   GOOGLE_CLIENT_ID=
+   GOOGLE_CLIENT_SECRET=
    ```
 
 2. To generate AUTH_SECRET,
@@ -148,40 +160,41 @@ Which is https://[your-pull-zone-hostname]/[any folder name you might have added
 
    <img src="https://utfs.io/f/CUistsOk9f0IyM9047Pa7YvK8qbtnUAPO9jwxdskhzc2JNoR" alt=" CDN_BASE_ACCESS_URL"  width="600"  />
 
-
 # Steps to Set Up Google Maps Platform API Key
 
 To use the Google Maps API in your applications, follow the steps below to create and set up your API key.
 
 ### Step 1: Go to Google Cloud Console
+
 1. Navigate to the [Google Cloud Console](https://console.cloud.google.com/).
 2. If you don’t have a Google account, create one and sign in.
 
 ### Step 2: Create a New Project
+
 1. In the Cloud Console, click on the **Select a project** dropdown at the top.
 2. Click **New Project** to create a new project.
 3. Give your project a name, select the organization (optional), and choose the billing account.
 4. Click **Create**.
 
-### Step 3: Google Maps Platform 
+### Step 3: Google Maps Platform
+
 1. Search Google Maps Platform in the Console search bar
-<img width="1438" alt="Screenshot 2024-09-22 at 10 15 15 AM" src="https://github.com/user-attachments/assets/a5f93c1e-d7b6-4a5b-847b-868b1133643d">
+   <img width="1438" alt="Screenshot 2024-09-22 at 10 15 15 AM" src="https://github.com/user-attachments/assets/a5f93c1e-d7b6-4a5b-847b-868b1133643d">
 
 2. If your account is not setup yet , finish your account setup
-<img width="930" alt="Screenshot 2024-09-22 at 10 02 59 AM" src="https://github.com/user-attachments/assets/c8ee7aa3-7610-4836-86f6-c28e8604c2b9">
+   <img width="930" alt="Screenshot 2024-09-22 at 10 02 59 AM" src="https://github.com/user-attachments/assets/c8ee7aa3-7610-4836-86f6-c28e8604c2b9">
 
-3.After Completeing account setup ,  select the "Keys and Credentails" Section.
+3.After Completeing account setup , select the "Keys and Credentails" Section.
 4.Then select the Create Credentials option , under which you can select the "API Key Option"
 <img width="1440" alt="Screenshot 2024-09-22 at 10 05 36 AM" src="https://github.com/user-attachments/assets/9e897c91-3282-4e28-8fdf-d920d6c4bc15">
 
 5. You will receive a API Key , add the key to the NEXT_PUBLIC_GOOGLE_MAPS_API_KEY in the .env
-<img width="660" alt="Screenshot 2024-09-22 at 10 19 33 AM" src="https://github.com/user-attachments/assets/adcb5a49-892e-43a1-b318-56b296280611">
-
-
+   <img width="660" alt="Screenshot 2024-09-22 at 10 19 33 AM" src="https://github.com/user-attachments/assets/adcb5a49-892e-43a1-b318-56b296280611">
 
 ### Step 4: Changes required to make it work on localhost
+
 1. Although the documentation mentions that without restriction , the API key will work everywhere, that is not the case for http requests.
-2. Add a restriction and mention your localhost along with your port  for it to start working on local ,  and save and continue
-<img width="694" alt="Screenshot 2024-09-22 at 10 06 44 AM" src="https://github.com/user-attachments/assets/3acfdf47-4b1d-480f-8172-0fbfa1c39f02">
+2. Add a restriction and mention your localhost along with your port for it to start working on local , and save and continue
+   <img width="694" alt="Screenshot 2024-09-22 at 10 06 44 AM" src="https://github.com/user-attachments/assets/3acfdf47-4b1d-480f-8172-0fbfa1c39f02">
 
 3. to test navigate to the http://localhost:3000/create , and test the "Where is the job located" input.
diff --git a/package.json b/package.json
index c4a08bcd..cc9844c7 100644
--- a/package.json
+++ b/package.json
@@ -57,14 +57,15 @@
     "clsx": "^2.1.1",
     "dayjs": "^1.11.13",
     "framer-motion": "^11.5.4",
-    "linkify-react": "^4.1.3",
     "jiti": "^1.21.6",
+    "linkify-react": "^4.1.3",
     "lodash": "^4.17.21",
     "lucide-react": "^0.426.0",
     "next": "^14.2.12",
     "next-auth": "^4.24.7",
     "next-themes": "^0.3.0",
     "nextjs-toploader": "^1.6.12",
+    "nodemailer": "^6.9.15",
     "react": "^18",
     "react-dom": "^18",
     "react-hook-form": "^7.52.2",
@@ -80,6 +81,7 @@
   "devDependencies": {
     "@types/bcryptjs": "^2.4.6",
     "@types/node": "^20",
+    "@types/nodemailer": "^6.4.16",
     "@types/react": "^18",
     "@types/react-dom": "^18",
     "@typescript-eslint/eslint-plugin": "^8.1.0",
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index e0995ab0..35e0af8c 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -10,12 +10,40 @@ datasource db {
 model User {
   id         String  @id @default(cuid())
   name       String
-  email      String  @unique
-  password   String
+
+  password   String?
   avatar     String?
   isVerified Boolean @default(false)
   role       Role    @default(USER)
   jobs       Job[]
+
+  email         String    @unique
+  emailVerified DateTime?
+  
+  oauthProvider   OauthProvider?  // Tracks OAuth provider (e.g., 'google')
+  oauthId String?
+
+  blockedByAdmin DateTime?
+  
+}
+
+enum OauthProvider {
+  GOOGLE
+}
+
+
+model VerificationToken {
+  token String
+  identifier String
+  createdAt  DateTime @default(now())
+  updatedAt  DateTime @updatedAt
+  type TokenType
+  @@unique([token,identifier])
+}
+
+enum  TokenType {
+  EMAIL_VERIFICATION
+  RESET_PASSWORD
 }
 
 model Job {
diff --git a/prisma/seed.ts b/prisma/seed.ts
index 71caed80..214ae561 100644
--- a/prisma/seed.ts
+++ b/prisma/seed.ts
@@ -298,6 +298,7 @@ async function seedUsers() {
               name: u.name,
               password: hashedPassword,
               role: u.role || Role.USER,
+              emailVerified: new Date(),
             },
             update: {},
           })
diff --git a/src/actions/auth.actions.ts b/src/actions/auth.actions.ts
new file mode 100644
index 00000000..6e6601d8
--- /dev/null
+++ b/src/actions/auth.actions.ts
@@ -0,0 +1,315 @@
+'use server';
+import {
+  EMAIL_VERIFICATION_LINK_RESENT_TIME,
+  PASSWORD_HASH_SALT_ROUNDS,
+  PENDING_EMAIL_VERIFICATION_USER_ID,
+} from '@/config/auth.config';
+import APP_PATHS from '@/config/path.config';
+import prisma from '@/config/prisma.config';
+import { serverEnv } from '@/env/server';
+import { withServerActionAsyncCatcher } from '@/lib/async-catch';
+import { ErrorHandler } from '@/lib/error';
+import {
+  SignupSchema,
+  SignupSchemaType,
+} from '@/lib/validators/auth.validator';
+import { ServerActionReturnType } from '@/types/api.types';
+import bcryptjs from 'bcryptjs';
+import { v4 as uuidv4 } from 'uuid';
+import { sendConfirmationEmail } from '@/lib/sendConfirmationEmail';
+import { cookies } from 'next/headers';
+import { SuccessResponse } from '@/lib/success';
+import { isTokenExpiredUtil } from '@/lib/utils';
+import { TokenType } from '@prisma/client';
+export const signUp = withServerActionAsyncCatcher<
+  SignupSchemaType,
+  ServerActionReturnType
+>(async (_data) => {
+  const data = SignupSchema.parse(_data);
+
+  const userExist = await prisma.user.findFirst({
+    where: { email: data.email },
+  });
+
+  if (userExist)
+    throw new ErrorHandler('User with this email already exist', 'BAD_REQUEST');
+
+  const hashedPassword = await bcryptjs.hash(
+    data.password,
+    PASSWORD_HASH_SALT_ROUNDS
+  );
+
+  try {
+    await prisma.$transaction(async (txn) => {
+      const user = await txn.user.create({
+        data: { ...data, password: hashedPassword },
+      });
+
+      const verificationToken = await txn.verificationToken.create({
+        data: {
+          identifier: user.id,
+          token: uuidv4(),
+          type: 'EMAIL_VERIFICATION',
+        },
+      });
+
+      const confirmationLink = `${serverEnv.BASE_URL}/${APP_PATHS.VERIFY_EMAIL}/${verificationToken.token}`;
+
+      await sendConfirmationEmail(
+        data.email,
+        confirmationLink,
+        'EMAIL_VERIFICATION'
+      );
+
+      cookies().set(PENDING_EMAIL_VERIFICATION_USER_ID, user.id, {
+        maxAge: 5 * 60, // 5 minutes
+        httpOnly: true,
+        secure: process.env.NODE_ENV === 'production',
+      });
+
+      return user;
+    });
+
+    return new SuccessResponse(
+      'User registered successfully. A verification link has been sent to your email.',
+      201
+    ).serialize();
+  } catch {
+    throw new ErrorHandler(
+      'Registration Failed, please try again!',
+      'INTERNAL_SERVER_ERROR'
+    );
+  }
+});
+
+export const resendVerificationEmail = withServerActionAsyncCatcher<
+  null,
+  ServerActionReturnType
+>(async () => {
+  const unverifiedUserId = cookies().get(
+    PENDING_EMAIL_VERIFICATION_USER_ID
+  )?.value;
+
+  if (!unverifiedUserId)
+    throw new ErrorHandler('Resource not found!', 'BAD_REQUEST');
+
+  const unverifiedUser = await prisma.user.findFirst({
+    where: { id: unverifiedUserId, emailVerified: null },
+  });
+
+  if (!unverifiedUser)
+    throw new ErrorHandler('Resource not found!', 'BAD_REQUEST');
+
+  const verificationToken = await prisma.verificationToken.findFirst({
+    where: { identifier: unverifiedUserId, type: 'EMAIL_VERIFICATION' },
+  });
+
+  if (!verificationToken)
+    throw new ErrorHandler('Resource not found!', 'BAD_REQUEST');
+
+  if (isTokenExpiredUtil(verificationToken.createdAt))
+    throw new ErrorHandler('Link expired!', 'BAD_REQUEST', {
+      linkExpired: true,
+    });
+
+  const now = new Date().getTime();
+
+  // last time update i.e. token was updated
+  const updatedAt = new Date(verificationToken.updatedAt).getTime();
+  const isTooEarlyToResend =
+    now - updatedAt < EMAIL_VERIFICATION_LINK_RESENT_TIME * 1000;
+  if (isTooEarlyToResend)
+    throw new ErrorHandler('Too much request', 'BAD_REQUEST');
+
+  // TODO: should we not delete the user record from db
+  await resendVerificationLinkUtil({
+    userId: unverifiedUser.id,
+    email: unverifiedUser.email,
+    prevToken: verificationToken.token,
+    type: 'EMAIL_VERIFICATION',
+  });
+
+  return new SuccessResponse(
+    'Verfication link resent successfully!',
+    201
+  ).serialize();
+});
+
+const resendVerificationLinkUtil = async ({
+  userId,
+  email,
+  prevToken,
+  reIssue = false,
+  type,
+}: {
+  userId: string;
+  email: string;
+  prevToken: string;
+  reIssue?: boolean;
+  type: TokenType;
+}) => {
+  const newToken = uuidv4();
+  await prisma.verificationToken.update({
+    where: {
+      token_identifier: {
+        identifier: userId,
+        token: prevToken,
+      },
+      type,
+    },
+    data: { token: newToken, ...(reIssue ? { createdAt: new Date() } : {}) },
+  });
+
+  const confirmationLink = `${serverEnv.BASE_URL}/${APP_PATHS.VERIFY_EMAIL}/${newToken}`;
+  await sendConfirmationEmail(email, confirmationLink, type);
+};
+
+// It is serving two purpose/
+// 1. Email verification
+// 2. In case link got expired, by passing resend:true will be re-usable to re-issue the verfication link
+export const verifyEmail = withServerActionAsyncCatcher<
+  { token: string; resend?: boolean },
+  ServerActionReturnType
+>(async ({ token, resend = false }) => {
+  let verificationToken = await prisma.verificationToken.findFirst({
+    where: { token, type: 'EMAIL_VERIFICATION' },
+  });
+
+  if (!verificationToken)
+    throw new ErrorHandler('Resource not found!', 'BAD_REQUEST', {
+      notFound: true,
+    });
+
+  if (!isTokenExpiredUtil(verificationToken.createdAt)) {
+    await prisma.$transaction(async (txn) => {
+      await txn.user.update({
+        where: { id: verificationToken.identifier },
+        data: { emailVerified: new Date() },
+      });
+
+      await txn.verificationToken.delete({
+        where: {
+          token_identifier: {
+            token: verificationToken.token,
+            identifier: verificationToken.identifier,
+          },
+        },
+      });
+
+      return true;
+    });
+    cookies().delete(PENDING_EMAIL_VERIFICATION_USER_ID);
+    return new SuccessResponse('Email verified successfully!', 201).serialize();
+  }
+
+  if (!resend) {
+    throw new ErrorHandler('Link expired!', 'BAD_REQUEST', {
+      linkExpired: true,
+    });
+  }
+
+  const unverifiedUser = await prisma.user.findFirst({
+    where: { id: verificationToken.identifier },
+  });
+
+  await resendVerificationLinkUtil({
+    email: unverifiedUser!.email,
+    prevToken: verificationToken.token,
+    userId: unverifiedUser!.id,
+    reIssue: true,
+    type: 'EMAIL_VERIFICATION',
+  });
+
+  return new SuccessResponse(
+    'Verfication link resent successfully!',
+    201
+  ).serialize();
+});
+
+export const forgetPassword = withServerActionAsyncCatcher<
+  { email: string },
+  ServerActionReturnType
+>(async ({ email }) => {
+  const user = await prisma.user.findFirst({ where: { email } });
+
+  if (!user)
+    throw new ErrorHandler(
+      'No account associated with this email address.',
+      'BAD_REQUEST'
+    );
+
+  const verificationToken = await prisma.verificationToken.create({
+    data: {
+      type: 'RESET_PASSWORD',
+      token: uuidv4(),
+      identifier: user.id,
+    },
+  });
+
+  const resetPasswordLink = `${serverEnv.BASE_URL}/${APP_PATHS.RESET_PASSWORD}/${verificationToken.token}`;
+
+  await sendConfirmationEmail(email, resetPasswordLink, 'RESET_PASSWORD');
+
+  return new SuccessResponse(
+    'A password reset link has been sent to your email. Please check your inbox.',
+    201
+  ).serialize();
+});
+
+export const resetPassword = withServerActionAsyncCatcher<
+  {
+    token: string;
+    password: string;
+    confirmPassword: string;
+  },
+  ServerActionReturnType
+>(async ({ token, password, confirmPassword }) => {
+  if (password !== confirmPassword)
+    throw new ErrorHandler('Password does not match.', 'BAD_REQUEST');
+
+  const verificationToken = await prisma.verificationToken.findFirst({
+    where: { token },
+  });
+
+  if (!verificationToken)
+    throw new ErrorHandler('Invalid or expired reset link.', 'BAD_REQUEST');
+
+  if (isTokenExpiredUtil(verificationToken.createdAt))
+    throw new ErrorHandler(
+      'The reset link has expired. Please request a new one.',
+      'BAD_REQUEST'
+    );
+
+  const user = await prisma.user.findFirst({
+    where: { id: verificationToken.identifier },
+  });
+
+  if (!user)
+    throw new ErrorHandler(
+      'Unauthorized access. User not found.',
+      'AUTHENTICATION_FAILED'
+    );
+
+  await prisma.$transaction(async (txn) => {
+    await txn.user.update({
+      where: { id: verificationToken.identifier },
+      data: {
+        password: await bcryptjs.hash(password, PASSWORD_HASH_SALT_ROUNDS),
+      },
+    });
+
+    await txn.verificationToken.delete({
+      where: {
+        token_identifier: {
+          token: verificationToken.token,
+          identifier: verificationToken.identifier,
+        },
+      },
+    });
+  });
+
+  return new SuccessResponse(
+    'Your password has been successfully updated.',
+    201
+  ).serialize();
+});
diff --git a/src/actions/job.action.ts b/src/actions/job.action.ts
index 2d104754..f0a9c066 100644
--- a/src/actions/job.action.ts
+++ b/src/actions/job.action.ts
@@ -15,11 +15,16 @@ import {
 } from '@/lib/validators/jobs.validator';
 import { getJobFilters } from '@/services/jobs.services';
 import { ServerActionReturnType } from '@/types/api.types';
+ 
+import { getServerSession } from 'next-auth';
+import { authOptions } from '@/lib/authOptions';
+ 
 import {
   getAllJobsAdditonalType,
   getAllRecommendedJobs,
   getJobType,
 } from '@/types/jobs.types';
+ 
 
 type additional = {
   isVerifiedJob: boolean;
@@ -28,6 +33,10 @@ export const createJob = withServerActionAsyncCatcher<
   JobPostSchemaType,
   ServerActionReturnType<additional>
 >(async (data) => {
+  const auth = await getServerSession(authOptions);
+  if (!auth || !auth?.user?.id)
+    throw new ErrorHandler('Not Authrised', 'UNAUTHORIZED');
+
   const result = JobPostSchema.parse(data);
   const {
     companyName,
@@ -48,7 +57,7 @@ export const createJob = withServerActionAsyncCatcher<
   } = result;
   await prisma.job.create({
     data: {
-      userId: '1', // Default to 1 since there's no session to check for user id
+      userId: auth.user.id,
       title,
       description,
       companyName,
@@ -293,3 +302,38 @@ export const getRecentJobs = async () => {
     return new ErrorHandler('Internal server error', 'DATABASE_ERROR');
   }
 };
+
+export const updateJob = withServerActionAsyncCatcher<
+  JobPostSchemaType & { jobId: string },
+  ServerActionReturnType<additional>
+>(async (data) => {
+  const auth = await getServerSession(authOptions);
+  if (!auth || !auth?.user?.id)
+    throw new ErrorHandler('Not Authorized', 'UNAUTHORIZED');
+
+  const { jobId, ...updateData } = data;
+  const parsedId = JobByIdSchema.parse({ id: jobId });
+
+  const result = JobPostSchema.parse(updateData);
+
+  let job = await prisma.job.findFirst({
+    where: { id: parsedId.id, userId: auth.user.id },
+  });
+
+  if (!job)
+    throw new ErrorHandler('Job not found or not authorized', 'NOT_FOUND');
+
+  // Update the job
+  job = await prisma.job.update({
+    where: { id: parsedId.id },
+    data: { ...result, isVerifiedJob: false },
+  });
+
+  const additonal = { isVerifiedJob: false, jobId: job.id };
+
+  return new SuccessResponse(
+    'Job updated successfully',
+    200,
+    additonal
+  ).serialize();
+});
diff --git a/src/app/(auth)/forgot-password/page.tsx b/src/app/(auth)/forgot-password/page.tsx
new file mode 100644
index 00000000..342cc9b5
--- /dev/null
+++ b/src/app/(auth)/forgot-password/page.tsx
@@ -0,0 +1,18 @@
+import { ForgotPassword } from '@/components/auth/forgot-password';
+import { FormContainer } from '@/layouts/form-container';
+import React from 'react';
+
+const ForgootPasswordPage = async () => {
+  return (
+    <div className="my-20">
+      <FormContainer
+        heading={'Welcome back!'}
+        description={'Enter your details below to continue with your sign-in.'}
+      >
+        <ForgotPassword />
+      </FormContainer>
+    </div>
+  );
+};
+
+export default ForgootPasswordPage;
diff --git a/src/app/(auth)/layout.tsx b/src/app/(auth)/layout.tsx
new file mode 100644
index 00000000..da5ec1ec
--- /dev/null
+++ b/src/app/(auth)/layout.tsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import { authOptions } from '@/lib/authOptions';
+import { getServerSession } from 'next-auth';
+import { redirect } from 'next/navigation';
+
+export default async function AuthLayout({
+  children,
+}: {
+  children: React.ReactNode;
+}) {
+  const auth = await getServerSession(authOptions);
+
+  if (auth) redirect(`/`);
+
+  return children;
+}
diff --git a/src/app/(auth)/reset-password/[token]/page.tsx b/src/app/(auth)/reset-password/[token]/page.tsx
new file mode 100644
index 00000000..b137f9fc
--- /dev/null
+++ b/src/app/(auth)/reset-password/[token]/page.tsx
@@ -0,0 +1,40 @@
+import { ResetPassword } from '@/components/auth/reset-password';
+import prisma from '@/config/prisma.config';
+import { FormContainer } from '@/layouts/form-container';
+import { isTokenExpiredUtil } from '@/lib/utils';
+import { notFound } from 'next/navigation';
+import React from 'react';
+
+const ResetPasswordPage = async ({
+  params: { token },
+}: {
+  params: { token: string };
+}) => {
+  const verificatinToken = await prisma.verificationToken.findFirst({
+    where: { token },
+  });
+
+  if (!verificatinToken) notFound();
+
+  if (isTokenExpiredUtil(verificatinToken.createdAt))
+    return <h1>link expried</h1>;
+
+  const user = await prisma.user.findFirst({
+    where: { id: verificatinToken.identifier },
+  });
+
+  if (!user) notFound();
+
+  return (
+    <div className="my-20">
+      <FormContainer
+        heading={'Welcome back!'}
+        description={'Enter your details below to continue with your sign-in.'}
+      >
+        <ResetPassword />
+      </FormContainer>
+    </div>
+  );
+};
+
+export default ResetPasswordPage;
diff --git a/src/app/(auth)/signin/page.tsx b/src/app/(auth)/signin/page.tsx
new file mode 100644
index 00000000..c81f3395
--- /dev/null
+++ b/src/app/(auth)/signin/page.tsx
@@ -0,0 +1,17 @@
+import { Signin } from '@/components/auth/signin';
+import { FormContainer } from '@/layouts/form-container';
+
+const LoginPage = () => {
+  return (
+    <div className="my-20">
+      <FormContainer
+        heading={'Welcome back'}
+        description={'Please enter your details to sign in.'}
+      >
+        <Signin />
+      </FormContainer>
+    </div>
+  );
+};
+
+export default LoginPage;
diff --git a/src/app/(auth)/signup/page.tsx b/src/app/(auth)/signup/page.tsx
new file mode 100644
index 00000000..f3e6ef8c
--- /dev/null
+++ b/src/app/(auth)/signup/page.tsx
@@ -0,0 +1,17 @@
+import { Signup } from '@/components/auth/signup';
+import { FormContainer } from '@/layouts/form-container';
+
+const SignupPage = () => {
+  return (
+    <div className="my-20">
+      <FormContainer
+        heading={'Welcome to 100xJobs'}
+        description={'Please enter your details to sign up.'}
+      >
+        <Signup />
+      </FormContainer>
+    </div>
+  );
+};
+
+export default SignupPage;
diff --git a/src/app/(auth)/verify-email/[token]/EmailVerificationLinkExpired.tsx b/src/app/(auth)/verify-email/[token]/EmailVerificationLinkExpired.tsx
new file mode 100644
index 00000000..a2bf0bc9
--- /dev/null
+++ b/src/app/(auth)/verify-email/[token]/EmailVerificationLinkExpired.tsx
@@ -0,0 +1,54 @@
+'use client';
+import { useState } from 'react';
+import { FormContainer } from '@/layouts/form-container';
+import Link from 'next/link';
+import APP_PATHS from '@/config/path.config';
+import { Button } from '@/components/ui/button';
+import { verifyEmail } from '@/actions/auth.actions';
+import { useToast } from '@/components/ui/use-toast';
+
+export const EmailVerificationLinkExpired = ({ token }: { token: string }) => {
+  const [isEmailSent, setIsEmailSent] = useState(false);
+  const [isLoading, setIsLoading] = useState(false);
+  const { toast } = useToast();
+
+  const handleResendClick = async () => {
+    setIsLoading(true);
+    try {
+      await verifyEmail({ token, resend: true });
+      setIsEmailSent(true);
+    } catch {
+      toast({
+        variant: 'destructive',
+        title: 'Something went wrong, please try again!',
+      });
+    } finally {
+      setIsLoading(!true);
+    }
+  };
+
+  return (
+    <div className="my-20">
+      <FormContainer
+        heading={'Link Expired!'}
+        description={
+          isEmailSent
+            ? 'We’ve sent a confirmation email to your inbox. Please confirm your email address to activate your account.'
+            : 'The verification link has expired or is invalid. Please request a new verification link.'
+        }
+      >
+        {!isEmailSent ? (
+          <Link href={APP_PATHS.SIGNIN}>
+            <Button className="w-full" disabled={isLoading}>
+              Go to Login
+            </Button>
+          </Link>
+        ) : (
+          <Link href={APP_PATHS.SIGNIN} onClick={handleResendClick}>
+            <Button className="w-full">Resend Verification Email</Button>
+          </Link>
+        )}
+      </FormContainer>
+    </div>
+  );
+};
diff --git a/src/app/(auth)/verify-email/[token]/page.tsx b/src/app/(auth)/verify-email/[token]/page.tsx
new file mode 100644
index 00000000..0a64b44a
--- /dev/null
+++ b/src/app/(auth)/verify-email/[token]/page.tsx
@@ -0,0 +1,52 @@
+import { verifyEmail } from '@/actions/auth.actions';
+import { Button } from '@/components/ui/button';
+import APP_PATHS from '@/config/path.config';
+import { FormContainer } from '@/layouts/form-container';
+import Link from 'next/link';
+import { redirect } from 'next/navigation';
+import React from 'react';
+import { EmailVerificationLinkExpired } from './EmailVerificationLinkExpired';
+
+const Page = async ({ params: { token } }: { params: { token: string } }) => {
+  const res = await verifyEmail({ token });
+
+  if (res.status) return <EmailVerifiedSuccess />;
+  else if (res?.error?.notFound) return <EmailVerificationLinkNotFound />;
+  else if (res?.error?.linkExpired)
+    return <EmailVerificationLinkExpired token={token} />;
+  return redirect(APP_PATHS.SIGNIN);
+};
+
+export default Page;
+
+const EmailVerifiedSuccess = () => {
+  return (
+    <div className="my-20">
+      <FormContainer
+        heading={'Email Verified!'}
+        description={
+          'Your email has been successfully verified. You can now access your account.'
+        }
+      >
+        <Link href={APP_PATHS.SIGNIN}>
+          <Button className="w-full">Go to Login</Button>
+        </Link>
+      </FormContainer>
+    </div>
+  );
+};
+
+const EmailVerificationLinkNotFound = () => {
+  return (
+    <div className="my-20">
+      <FormContainer
+        heading={'Link Not Found'}
+        description={'The verification link you used is invalid or not found.'}
+      >
+        <Link href={APP_PATHS.SIGNUP}>
+          <Button className="w-full">Go to Signup</Button>
+        </Link>
+      </FormContainer>
+    </div>
+  );
+};
diff --git a/src/app/(auth)/welcome/page.tsx b/src/app/(auth)/welcome/page.tsx
new file mode 100644
index 00000000..ec06b53d
--- /dev/null
+++ b/src/app/(auth)/welcome/page.tsx
@@ -0,0 +1,27 @@
+import { Welcome } from '@/components/auth/welcome';
+import APP_PATHS from '@/config/path.config';
+import { FormContainer } from '@/layouts/form-container';
+
+import { cookies } from 'next/headers';
+import { redirect } from 'next/navigation';
+import { PENDING_EMAIL_VERIFICATION_USER_ID } from '@/config/auth.config';
+
+const WelcomePage = () => {
+  const unverifiedUserId = cookies().get(PENDING_EMAIL_VERIFICATION_USER_ID);
+  if (!unverifiedUserId) redirect(APP_PATHS.SIGNIN);
+
+  return (
+    <div className="my-20">
+      <FormContainer
+        heading={'Check Your Email!'}
+        description={
+          'We’ve sent a confirmation email to your inbox. Please confirm your email address to activate your account.'
+        }
+      >
+        <Welcome />
+      </FormContainer>
+    </div>
+  );
+};
+
+export default WelcomePage;
diff --git a/src/app/api/auth/[...nextauth]/route.ts b/src/app/api/auth/[...nextauth]/route.ts
new file mode 100644
index 00000000..47c6692d
--- /dev/null
+++ b/src/app/api/auth/[...nextauth]/route.ts
@@ -0,0 +1,6 @@
+import { authOptions } from '@/lib/authOptions';
+import NextAuth from 'next-auth/next';
+
+const handler = NextAuth(authOptions);
+// export default handler;
+export { handler as GET, handler as POST };
diff --git a/src/components/auth/forgot-password.tsx b/src/components/auth/forgot-password.tsx
new file mode 100644
index 00000000..ad4b8f8b
--- /dev/null
+++ b/src/components/auth/forgot-password.tsx
@@ -0,0 +1,60 @@
+'use client';
+import { Label } from '../ui/label';
+import { Input } from '../ui/input';
+
+import { Button } from '../ui/button';
+import { FormEvent, useState } from 'react';
+import { useToast } from '../ui/use-toast';
+import { forgetPassword } from '@/actions/auth.actions';
+
+export const ForgotPassword = () => {
+  const [isLoading, setIsLoading] = useState(false);
+  const [email, setEmail] = useState('');
+  const { toast } = useToast();
+
+  const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
+    e.preventDefault();
+    setIsLoading(true);
+
+    try {
+      const res = await forgetPassword({ email });
+
+      toast({
+        title: res.message,
+        variant: res.status ? 'success' : 'destructive',
+      });
+    } catch {
+      toast({
+        title:
+          "We're sorry for the inconvenience. Please report this issue to our support team",
+        variant: 'destructive',
+      });
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  return (
+    <form
+      onSubmit={handleSubmit}
+      className="grid w-full max-w-sm items-center gap-4"
+    >
+      <Label htmlFor="email">Email</Label>
+
+      <Input
+        type="email"
+        id="email"
+        placeholder="Email"
+        required={true}
+        value={email}
+        onChange={(e) => {
+          setEmail(e.target.value);
+        }}
+      />
+
+      <Button type="submit" className="mt-4" disabled={isLoading}>
+        Submit
+      </Button>
+    </form>
+  );
+};
diff --git a/src/components/auth/reset-password.tsx b/src/components/auth/reset-password.tsx
new file mode 100644
index 00000000..7ffa25f0
--- /dev/null
+++ b/src/components/auth/reset-password.tsx
@@ -0,0 +1,122 @@
+'use client';
+import { useParams } from 'next/navigation';
+import React, { FormEvent, useState } from 'react';
+import { Label } from '../ui/label';
+import { Input } from '../ui/input';
+import { Button } from '../ui/button';
+import { resetPassword } from '@/actions/auth.actions';
+import { useToast } from '../ui/use-toast';
+import { useRouter } from 'next/navigation';
+import APP_PATHS from '@/config/path.config';
+import { EyeIcon, EyeOffIcon } from 'lucide-react';
+
+export const ResetPassword = () => {
+  const params = useParams();
+
+  const token = params.token;
+
+  const [data, setData] = useState({
+    password: '',
+    confirmPassword: '',
+  });
+
+  const [isLoading, setIsLoading] = useState(false);
+  const [errorMessage, setErrorMessage] = useState('');
+  const { toast } = useToast();
+  const router = useRouter();
+
+  const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
+    e.preventDefault();
+    if (data.confirmPassword !== data.password) {
+      setErrorMessage('Password must be identical!');
+      return;
+    }
+    setIsLoading(true);
+    try {
+      const res = await resetPassword({
+        ...data,
+        token: token as string,
+      });
+      toast({
+        variant: res.status ? 'default' : 'destructive',
+        title: res.message,
+      });
+
+      router.replace(APP_PATHS.SIGNIN);
+    } catch {
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  return (
+    <form
+      onSubmit={handleSubmit}
+      className="grid w-full max-w-sm items-center gap-4"
+    >
+      <div className="space-y-2">
+        <Label htmlFor="email">Password</Label>
+
+        <PasswordInput
+          placeholder="Enter your password"
+          value={data.password}
+          onChange={(e) =>
+            setData((prev) => ({ ...prev, password: e.target.value }))
+          }
+        />
+      </div>
+      <div className="space-y-2">
+        <Label htmlFor="email">Confirm Password</Label>
+        <PasswordInput
+          placeholder="Confirm your password"
+          value={data.confirmPassword}
+          onChange={(e) =>
+            setData((prev) => ({ ...prev, confirmPassword: e.target.value }))
+          }
+        />
+      </div>
+      {errorMessage ? (
+        <p className="text-sm font-medium text-destructive">{errorMessage}</p>
+      ) : null}
+      <Button type="submit" disabled={isLoading}>
+        Submit
+      </Button>
+    </form>
+  );
+};
+
+interface PasswordInputProps {
+  placeholder?: string;
+  value: string;
+  onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
+}
+
+export const PasswordInput = ({
+  placeholder,
+  value,
+  onChange,
+}: PasswordInputProps) => {
+  const [showPassword, setShowPassword] = useState(false);
+
+  const togglePasswordVisibility = () => {
+    setShowPassword(!showPassword);
+  };
+
+  return (
+    <div className="relative">
+      <Input
+        type={showPassword ? 'text' : 'password'}
+        value={value}
+        onChange={onChange}
+        placeholder={placeholder || '••••••••'}
+      />
+      <button
+        type="button"
+        onClick={togglePasswordVisibility}
+        className="absolute right-2 top-1/2 transform -translate-y-1/2 focus:outline-none"
+      >
+        {showPassword ? <EyeOffIcon /> : <EyeIcon />}
+      </button>
+    </div>
+  );
+};
diff --git a/src/components/auth/signin.tsx b/src/components/auth/signin.tsx
new file mode 100644
index 00000000..4c15d239
--- /dev/null
+++ b/src/components/auth/signin.tsx
@@ -0,0 +1,129 @@
+'use client';
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/ui/input';
+import APP_PATHS from '@/config/path.config';
+import {
+  SigninSchema,
+  SigninSchemaType,
+} from '@/lib/validators/auth.validator';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { signIn } from 'next-auth/react';
+import Link from 'next/link';
+import { useRouter } from 'next/navigation';
+import { useForm } from 'react-hook-form';
+import {
+  Form,
+  FormControl,
+  FormField,
+  FormItem,
+  FormLabel,
+  FormMessage,
+} from '../ui/form';
+import { useToast } from '../ui/use-toast';
+import { DemarcationLine, GoogleOauthButton } from './social-auth';
+import { PasswordInput } from '../password-input';
+
+export const Signin = () => {
+  const { toast } = useToast();
+  const router = useRouter();
+
+  const form = useForm<SigninSchemaType>({
+    resolver: zodResolver(SigninSchema),
+    defaultValues: {
+      email: '',
+      password: '',
+    },
+  });
+
+  async function signinHandler(data: SigninSchemaType) {
+    try {
+      const response = await signIn('signin', { ...data, redirect: false });
+      if (!response?.ok) {
+        return toast({
+          title: response?.error || 'Internal server error',
+          variant: 'destructive',
+        });
+      }
+      toast({
+        title: 'Login successful! Welcome back!',
+        variant: 'success',
+      });
+      // const redirect = searchParams.get('next') || APP_PATHS.HOME;
+      const searchParams = new URLSearchParams(window.location.search);
+      const redirect = searchParams.get('next') || APP_PATHS.HOME;
+      router.push(redirect);
+    } catch (_error) {
+      return toast({
+        title: 'Internal server error',
+        variant: 'destructive',
+      });
+    }
+  }
+
+  return (
+    <div className="">
+      <Form {...form}>
+        <form
+          onSubmit={form.handleSubmit(signinHandler)}
+          className="w-full space-y-6"
+        >
+          <FormField
+            control={form.control}
+            name="email"
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>Email address</FormLabel>
+                <FormControl>
+                  <Input {...field} placeholder="name@gmail.com" />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+
+          <FormField
+            control={form.control}
+            name="password"
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>Password</FormLabel>
+                <FormControl>
+                  <PasswordInput field={field} placeholder="Password" />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+          <div className="flex justify-end">
+            <Link
+              href={APP_PATHS.FORGOT_PASSWORD}
+              className="text-xs text-muted-foreground font-medium hover:underline"
+            >
+              Forget your password?
+            </Link>
+          </div>
+          <Button
+            type="submit"
+            disabled={form.formState.isSubmitting}
+            className="w-full h-10"
+          >
+            {form.formState.isSubmitting ? 'Please wait...' : 'Sign In'}
+          </Button>
+          <DemarcationLine />
+          <GoogleOauthButton label="Sign in with Google" />
+        </form>
+      </Form>
+      <div className="flex items-center justify-center mt-6">
+        <span className="text-muted-foreground">
+          Don&apos;t have an account yet?{' '}
+          <Link
+            href={APP_PATHS.SIGNUP}
+            className="text-muted-foreground font-semibold hover:underline"
+          >
+            Sign Up
+          </Link>
+        </span>
+      </div>
+    </div>
+  );
+};
diff --git a/src/components/auth/signup.tsx b/src/components/auth/signup.tsx
new file mode 100644
index 00000000..70aac2fb
--- /dev/null
+++ b/src/components/auth/signup.tsx
@@ -0,0 +1,143 @@
+'use client';
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/ui/input';
+import APP_PATHS from '@/config/path.config';
+import {
+  SignupSchema,
+  SignupSchemaType,
+} from '@/lib/validators/auth.validator';
+import { zodResolver } from '@hookform/resolvers/zod';
+
+import Link from 'next/link';
+import { useRouter } from 'next/navigation';
+import { useForm } from 'react-hook-form';
+import {
+  Form,
+  FormControl,
+  FormField,
+  FormItem,
+  FormLabel,
+  FormMessage,
+} from '../ui/form';
+import { useToast } from '../ui/use-toast';
+import { signUp } from '@/actions/auth.actions';
+import { DemarcationLine, GoogleOauthButton } from './social-auth';
+import { PasswordInput } from '../password-input';
+
+export const Signup = () => {
+  const { toast } = useToast();
+  const router = useRouter();
+
+  const form = useForm<SignupSchemaType>({
+    resolver: zodResolver(SignupSchema),
+    defaultValues: {
+      name: '',
+      email: '',
+      password: '',
+    },
+  });
+
+  async function signupHandler(data: SignupSchemaType) {
+    try {
+      const response = await signUp(data);
+
+      if (!response.status) {
+        toast({
+          title: response.message || 'Something went wrong',
+          variant: 'destructive',
+        });
+      } else {
+        toast({
+          title: response.message || 'Signup successful! Welcome to 100xJobs!',
+          variant: 'success',
+        });
+
+        router.push(APP_PATHS.WELCOME);
+      }
+    } catch {
+      toast({
+        title: 'something went wrong',
+        variant: 'destructive',
+      });
+    }
+  }
+
+  return (
+    <>
+      <Form {...form}>
+        <form
+          onSubmit={form.handleSubmit(signupHandler)}
+          className="w-full space-y-6"
+        >
+          <FormField
+            control={form.control}
+            name="name"
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>Name</FormLabel>
+                <FormControl>
+                  <Input {...field} placeholder="Jhon Doe" />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+          <FormField
+            control={form.control}
+            name="email"
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>Email address</FormLabel>
+                <FormControl>
+                  <Input {...field} placeholder="name@gmail.com" />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+          <FormField
+            control={form.control}
+            name="password"
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>Password</FormLabel>
+                <FormControl>
+                  <PasswordInput field={field} placeholder="Password" />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+          <div className="flex justify-end">
+            <Link
+              href={APP_PATHS.FORGOT_PASSWORD}
+              className="text-xs text-muted-foreground font-medium hover:underline"
+            >
+              Forget your password?
+            </Link>
+          </div>
+          <Button
+            type="submit"
+            disabled={form.formState.isSubmitting}
+            className="w-full h-10"
+          >
+            {form.formState.isSubmitting ? 'Please wait...' : 'Create Account'}
+          </Button>
+          <DemarcationLine />
+          <GoogleOauthButton label="Sign un with Google" />
+        </form>
+      </Form>
+      <div className="flex items-center justify-center mt-6">
+        <span className="text-muted-foreground">
+          Already have an account?{' '}
+          <Link
+            href={APP_PATHS.SIGNIN}
+            className="text-muted-foreground font-semibold hover:underline"
+          >
+            Sign In
+          </Link>
+        </span>
+      </div>
+    </>
+  );
+};
diff --git a/src/components/auth/social-auth.tsx b/src/components/auth/social-auth.tsx
new file mode 100644
index 00000000..7b7a8b09
--- /dev/null
+++ b/src/components/auth/social-auth.tsx
@@ -0,0 +1,39 @@
+'use client';
+
+import { Button } from '@/components/ui/button';
+
+import { signIn } from 'next-auth/react';
+export const DemarcationLine = () => (
+  <div className="flex items-center my-4">
+    <div className="flex-grow h-px bg-gray-300" />
+    <span className="px-4 text-sm text-gray-500">or continue with</span>
+    <div className="flex-grow h-px bg-gray-300" />
+  </div>
+);
+
+export const GoogleOauthButton = ({ label }: { label: string }) => (
+  <Button
+    onClick={(e) => {
+      e.preventDefault();
+      e.stopPropagation();
+      signIn('google');
+    }}
+    className="w-full h-10 bg-white border border-gray-300 text-gray-700 font-medium hover:bg-gray-50"
+  >
+    <svg
+      className="w-4 h-4 mr-2"
+      aria-hidden="true"
+      focusable="false"
+      data-prefix="fab"
+      data-icon="google"
+      xmlns="http://www.w3.org/2000/svg"
+      viewBox="0 0 488 512"
+    >
+      <path
+        fill="currentColor"
+        d="M488 261.8c0-17.8-1.6-35.6-4.9-52.9H249.2v99.4h135.3c-5.8 30-23.1 55.3-49.2 72.1v59.8h79.4c46.5-42.9 73.3-106 73.3-178.4zM249.2 480c65.7 0 120.7-21.8 160.9-59.2l-79.4-59.8c-22.2 14.9-50.5 23.7-81.5 23.7-62.7 0-115.8-42.3-134.7-99.2H33.8v62.1C74 428.7 157.5 480 249.2 480zM114.5 303.7c-7.8-22.8-7.8-47.5 0-70.3V171.3H33.8c-35.1 69.8-35.1 151.8 0 221.6l80.7-62.1zM249.2 97.4c35.8-.6 70.1 12.7 96.2 36.2l72.3-69.2C370.2 28.3 310.4 0 249.2 0 157.5 0 74 51.3 33.8 130.4l80.7 62.1c18.9-56.9 72-99.2 134.7-95.1z"
+      />
+    </svg>
+    {label}
+  </Button>
+);
diff --git a/src/components/auth/welcome.tsx b/src/components/auth/welcome.tsx
new file mode 100644
index 00000000..6967564a
--- /dev/null
+++ b/src/components/auth/welcome.tsx
@@ -0,0 +1,65 @@
+'use client';
+import React, { useEffect, useState } from 'react';
+import { Button } from '../ui/button';
+import APP_PATHS from '@/config/path.config';
+import { useRouter } from 'next/navigation';
+import { resendVerificationEmail } from '@/actions/auth.actions';
+import { EMAIL_VERIFICATION_LINK_RESENT_TIME } from '@/config/auth.config';
+
+export const Welcome = () => {
+  const router = useRouter();
+  return (
+    <div className="text-center p-4">
+      <p className="text-muted-foreground mb-4">
+        Didn’t receive the email? Click the button below to resend it.
+      </p>
+      <CountdownButton />
+      <Button
+        variant="link"
+        className="mt-4 text-primary underline"
+        onClick={() => router.push(APP_PATHS.SIGNIN)}
+      >
+        Go to Login
+      </Button>
+    </div>
+  );
+};
+
+const CountdownButton = () => {
+  const [isDisabled, setIsDisabled] = useState(true);
+  const resentTime = EMAIL_VERIFICATION_LINK_RESENT_TIME;
+  const [secondsRemaining, setSecondsRemaining] = useState(resentTime);
+
+  // Handler when button is clicked
+  const handleClick = async () => {
+    setIsDisabled(true);
+    setSecondsRemaining(resentTime);
+    await resendVerificationEmail(null);
+  };
+
+  // useEffect to handle the countdown logic
+  useEffect(() => {
+    if (secondsRemaining === 0 && isDisabled) {
+      setIsDisabled(false); // Enable the button once the countdown is over
+    }
+
+    let timer: NodeJS.Timeout;
+
+    if (isDisabled && secondsRemaining > 0) {
+      timer = setTimeout(() => {
+        setSecondsRemaining((prev) => prev - 1);
+      }, 1000); // Decrease the time every second
+    }
+
+    // Cleanup the timer
+    return () => clearTimeout(timer);
+  }, [isDisabled, secondsRemaining]);
+
+  return (
+    <Button onClick={handleClick} disabled={isDisabled} className="w-full">
+      {isDisabled
+        ? `Wait ${secondsRemaining} second${secondsRemaining !== 1 ? 's' : ''}...`
+        : 'Click Me'}
+    </Button>
+  );
+};
diff --git a/src/components/job-form.tsx b/src/components/job-form.tsx
index d9661b6f..06da8fb8 100644
--- a/src/components/job-form.tsx
+++ b/src/components/job-form.tsx
@@ -16,7 +16,7 @@ import {
   SelectValue,
 } from '@/components/ui/select';
 import { zodResolver } from '@hookform/resolvers/zod';
-import React, { useRef, useState } from 'react';
+import React, { useEffect, useRef, useState } from 'react';
 import { useForm } from 'react-hook-form';
 import {
   JobPostSchema,
@@ -39,8 +39,18 @@ const DynamicGmapsAutoSuggest = dynamic(() => import('./gmaps-autosuggest'), {
 });
 import { EmployementType } from '@prisma/client';
 import _ from 'lodash';
+import { useSession } from 'next-auth/react';
+import { useRouter } from 'next/navigation';
+import APP_PATHS from '@/config/path.config';
 
 const PostJobForm = () => {
+  const session = useSession();
+  const router = useRouter();
+  useEffect(() => {
+    if (session.status !== 'loading' && session.status === 'unauthenticated')
+      router.push(`${APP_PATHS.SIGNIN}?redirectTo=/create`);
+  }, [session.status]);
+
   const { toast } = useToast();
   const companyLogoImg = useRef<HTMLImageElement>(null);
   const form = useForm<JobPostSchemaType>({
@@ -157,6 +167,9 @@ const PostJobForm = () => {
     }
     form.setValue('companyLogo', 'https://wwww.example.com');
   }, [watchHasSalaryRange, form]);
+
+  if (session.status === 'loading') return null;
+
   return (
     <div className="flex flex-col items-center gap-y-10 justify-center">
       <div className="w-full md:justify-center mt-4 flex flex-col md:flex-row gap-2">
diff --git a/src/components/password-input.tsx b/src/components/password-input.tsx
new file mode 100644
index 00000000..2099ef12
--- /dev/null
+++ b/src/components/password-input.tsx
@@ -0,0 +1,33 @@
+import { useState } from 'react';
+import { Input } from './ui/input';
+import { EyeIcon, EyeOffIcon } from 'lucide-react';
+
+interface PasswordInputProps {
+  placeholder?: string;
+  field: any;
+}
+
+export const PasswordInput = ({ placeholder, field }: PasswordInputProps) => {
+  const [showPassword, setShowPassword] = useState(false);
+
+  const togglePasswordVisibility = () => {
+    setShowPassword(!showPassword);
+  };
+
+  return (
+    <div className="relative">
+      <Input
+        type={showPassword ? 'text' : 'password'}
+        {...field}
+        placeholder={placeholder || '••••••••'}
+      />
+      <button
+        type="button"
+        onClick={togglePasswordVisibility}
+        className="absolute right-2 top-1/2 transform -translate-y-1/2"
+      >
+        {showPassword ? <EyeOffIcon /> : <EyeIcon />}
+      </button>
+    </div>
+  );
+};
diff --git a/src/config/auth.config.ts b/src/config/auth.config.ts
index ce443428..f6d7040d 100644
--- a/src/config/auth.config.ts
+++ b/src/config/auth.config.ts
@@ -1,2 +1,7 @@
 export const AUTH_TOKEN_EXPIRATION_TIME = 30 * 24 * 60 * 60;
 export const PASSWORD_HASH_SALT_ROUNDS = 10;
+
+export const PENDING_EMAIL_VERIFICATION_USER_ID =
+  'PENDING_EMAIL_VERIFICATION_USER_ID';
+export const EMAIL_VERIFICATION_LINK_EXPIRATION_TIME = 24 * 60 * 60;
+export const EMAIL_VERIFICATION_LINK_RESENT_TIME = 0.5 * 60;
diff --git a/src/config/path.config.ts b/src/config/path.config.ts
index b5877d8f..266fb467 100644
--- a/src/config/path.config.ts
+++ b/src/config/path.config.ts
@@ -9,5 +9,8 @@ const APP_PATHS = {
   CONTACT_US: '',
   TESTIMONIALS: '#testimonials',
   FAQS: '#faq',
+  VERIFY_EMAIL: '/verify-email',
+  FORGOT_PASSWORD: '/forgot-password',
+  WELCOME: '/welcome',
 };
 export default APP_PATHS;
diff --git a/src/env/server.ts b/src/env/server.ts
index 3fa1d7dc..49ca3ca6 100644
--- a/src/env/server.ts
+++ b/src/env/server.ts
@@ -1,22 +1,32 @@
 // // server-env.ts
-// import { createEnv } from '@t3-oss/env-nextjs';
-// import { z } from 'zod';
+import { createEnv } from '@t3-oss/env-nextjs';
+import { z } from 'zod';
 
-// export const serverEnv = createEnv({
-//   server: {
-//     DATABASE_URL: z.string().url(),
-//     NEXTAUTH_SECRET: z.string().min(1),
-//     NEXTAUTH_URL: z.string().url(),
-//     CDN_API_KEY: z.string().min(1),
-//     CDN_BASE_UPLOAD_URL: z.string().url(),
-//     CDN_BASE_ACCESS_URL: z.string().url(),
-//   },
-//   runtimeEnv: {
-//     DATABASE_URL: process.env.DATABASE_URL,
-//     NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
-//     NEXTAUTH_URL: process.env.NEXTAUTH_URL,
-//     CDN_API_KEY: process.env.CDN_API_KEY,
-//     CDN_BASE_UPLOAD_URL: process.env.CDN_BASE_UPLOAD_URL,
-//     CDN_BASE_ACCESS_URL: process.env.CDN_BASE_ACCESS_URL,
-//   },
-// });
+export const serverEnv = createEnv({
+  server: {
+    DATABASE_URL: z.string().url(),
+    NEXTAUTH_SECRET: z.string().min(1),
+    NEXTAUTH_URL: z.string().url(),
+    CDN_API_KEY: z.string().min(1),
+    CDN_BASE_UPLOAD_URL: z.string().url(),
+    CDN_BASE_ACCESS_URL: z.string().url(),
+    BASE_URL: z.string().url(),
+    EMAIL_USER: z.string().min(1),
+    EMAIL_PASSWORD: z.string().min(1),
+    GOOGLE_CLIENT_ID: z.string().min(1),
+    GOOGLE_CLIENT_SECRET: z.string().min(1),
+  },
+  runtimeEnv: {
+    DATABASE_URL: process.env.DATABASE_URL,
+    NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
+    NEXTAUTH_URL: process.env.NEXTAUTH_URL,
+    CDN_API_KEY: process.env.CDN_API_KEY,
+    CDN_BASE_UPLOAD_URL: process.env.CDN_BASE_UPLOAD_URL,
+    CDN_BASE_ACCESS_URL: process.env.CDN_BASE_ACCESS_URL,
+    BASE_URL: process.env.BASE_URL,
+    EMAIL_USER: process.env.EMAIL_USER,
+    EMAIL_PASSWORD: process.env.EMAIL_PASSWORD,
+    GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID,
+    GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET,
+  },
+});  
diff --git a/src/layouts/header.tsx b/src/layouts/header.tsx
index 0121fc55..f4c5efb1 100644
--- a/src/layouts/header.tsx
+++ b/src/layouts/header.tsx
@@ -5,15 +5,16 @@ import {
   nonUserNavbar,
   userNavbar,
 } from '@/lib/constant/app.constant';
-import { useSession } from 'next-auth/react';
+import { signOut, useSession } from 'next-auth/react';
 import Link from 'next/link';
 import { NavItem } from '@/components/navitem';
 import Image from 'next/image';
 import { Skeleton } from '@/components/ui/skeleton';
-import { Moon, Sun } from 'lucide-react';
+import { LogOutIcon, Moon, Sun } from 'lucide-react';
 import { useTheme } from 'next-themes';
 import { ADMIN_ROLE } from '@/config/app.config';
 import { useEffect, useState } from 'react';
+import { Button } from '@/components/ui/button';
 export const CompanyLogo = () => {
   return (
     <div className="flex items-center gap-2">
@@ -68,6 +69,22 @@ const Header = () => {
                   : nonUserNavbar.map((item) => (
                       <NavItem {...item} key={item.id} />
                     ))}
+              {session.status === 'authenticated' ? (
+                <li>
+                  <Button
+                    className="rounded-lg"
+                    size="sm"
+                    variant="destructive"
+                  >
+                    <LogOutIcon
+                      className="w-4 h-4"
+                      onClick={() => {
+                        signOut();
+                      }}
+                    />
+                  </Button>
+                </li>
+              ) : null}
             </ul>
             <div className="flex items-center">
               {mounted && (
diff --git a/src/lib/async-catch.ts b/src/lib/async-catch.ts
index cc9f0341..4efc0628 100644
--- a/src/lib/async-catch.ts
+++ b/src/lib/async-catch.ts
@@ -1,11 +1,11 @@
 import { standardizeApiError } from './error';
 
-type withServerActionAsyncCatcherType<T, R> = (args?: T) => Promise<R>;
+type withServerActionAsyncCatcherType<T, R> = (args: T) => Promise<R>;
 
-function withServerActionAsyncCatcher<T, R>(
+export function withServerActionAsyncCatcher<T, R>(
   serverAction: withServerActionAsyncCatcherType<T, R>
 ): withServerActionAsyncCatcherType<T, R> {
-  return async (args?: T): Promise<R> => {
+  return async (args: T): Promise<R> => {
     try {
       return await serverAction(args);
     } catch (error) {
@@ -14,4 +14,20 @@ function withServerActionAsyncCatcher<T, R>(
   };
 }
 
-export { withServerActionAsyncCatcher };
+/**
+ * Usage example for empty args:
+ *
+ * export const serverAction = withServerActionAsyncCatcher<null, ServerActionReturnType>(
+ *   async () => {
+ *     return new SuccessResponse('message', 201, 'additional').serialize();
+ *   }
+ * );
+ * serverAction(null)
+ * Usage example for args with a defined type:
+ *
+ * export const serverActionWithArgs = withServerActionAsyncCatcher<{ name: string }, ServerActionReturnType>(
+ *   async (data) => {
+ *     return new SuccessResponse('message', 200).serialize();
+ *   }
+ * );
+ */
diff --git a/src/lib/auth.ts b/src/lib/auth.ts
index d4ad07d9..746faac5 100644
--- a/src/lib/auth.ts
+++ b/src/lib/auth.ts
@@ -42,7 +42,7 @@ export const options = {
           },
         });
 
-        if (!user)
+        if (!user || !user.password)
           throw new ErrorHandler(
             'Email or password is incorrect',
             'AUTHENTICATION_FAILED'
diff --git a/src/lib/authOptions.ts b/src/lib/authOptions.ts
new file mode 100644
index 00000000..15596431
--- /dev/null
+++ b/src/lib/authOptions.ts
@@ -0,0 +1,154 @@
+import { AUTH_TOKEN_EXPIRATION_TIME } from '@/config/auth.config';
+import prisma from '@/config/prisma.config';
+import bcrypt from 'bcryptjs';
+import { NextAuthOptions } from 'next-auth';
+import CredentialsProvider from 'next-auth/providers/credentials';
+import { ErrorHandler } from './error';
+import { SigninSchema } from './validators/auth.validator';
+import GoogleProvider from 'next-auth/providers/google';
+import { serverEnv } from '@/env/server';
+
+export const authOptions = {
+  providers: [
+    GoogleProvider({
+      clientId: serverEnv.GOOGLE_CLIENT_ID as string,
+      clientSecret: serverEnv.GOOGLE_CLIENT_SECRET as string,
+    }),
+    CredentialsProvider({
+      name: 'signin',
+      id: 'signin',
+      credentials: {
+        email: { label: 'Email', type: 'email', placeholder: 'email' },
+        password: { label: 'password', type: 'password' },
+      },
+      async authorize(credentials): Promise<any> {
+        const result = SigninSchema.safeParse(credentials);
+
+        if (!result.success) {
+          throw new ErrorHandler(
+            'Input Validation failed',
+            'VALIDATION_ERROR',
+            {
+              fieldErrors: result.error.flatten().fieldErrors,
+            }
+          );
+        }
+
+        const { email, password } = result.data;
+        const user = await prisma.user.findUnique({
+          where: {
+            email: email,
+            emailVerified: { not: null },
+            blockedByAdmin: null,
+          },
+          select: {
+            id: true,
+            name: true,
+            password: true,
+            role: true,
+            emailVerified: true,
+          },
+        });
+
+        if (!user || !user.password)
+          throw new ErrorHandler(
+            'Email or password is incorrect',
+            'AUTHENTICATION_FAILED'
+          );
+
+        const isPasswordMatched = await bcrypt.compare(password, user.password);
+
+        if (!isPasswordMatched) {
+          throw new ErrorHandler(
+            'Email or password is incorrect',
+            'AUTHENTICATION_FAILED'
+          );
+        }
+
+        return {
+          id: user.id,
+          name: user.name,
+          email: email,
+          isVerified: !!user.emailVerified,
+          role: user.role,
+        };
+      },
+    }),
+  ],
+  callbacks: {
+    async signIn(signInProps) {
+      let { user, account, profile } = signInProps;
+
+      if (account?.provider === 'google' && profile) {
+        const { id: oauthId, email, name, image: avatar } = user;
+
+        let existingUser = await prisma.user.findFirst({
+          where: {
+            OR: [{ email: email! }, { oauthId: oauthId! }],
+          },
+        });
+        if (existingUser?.blockedByAdmin) return false;
+
+        if (!existingUser) {
+          existingUser = await prisma.user.create({
+            data: {
+              oauthId,
+              oauthProvider: 'GOOGLE',
+              email: email as string,
+              name: name as string,
+              avatar,
+              emailVerified: new Date(),
+            },
+          });
+        }
+      }
+
+      return true;
+    },
+
+    async jwt(jwtProps) {
+      const { token, user, trigger, session } = jwtProps;
+      if (trigger === 'update') {
+        return {
+          ...token,
+          ...session.user,
+        };
+      }
+      if (user) {
+        const loggedInUser = await prisma.user.findFirst({
+          where: {
+            OR: [{ oauthId: { equals: user.id } }, { id: { equals: user.id } }],
+            blockedByAdmin: null,
+            emailVerified: { not: null },
+          },
+        });
+        if (!loggedInUser) return null;
+
+        token.id = loggedInUser.id;
+        token.name = user.name;
+        token.isVerified = user.isVerified;
+        token.role = user.role;
+      }
+      return token;
+    },
+
+    session({ session, token }) {
+      if (token && session && session.user) {
+        session.user.id = token.id;
+        session.user.isVerified = token.isVerified;
+        session.user.role = token.role;
+      }
+      return session;
+    },
+  },
+  session: {
+    strategy: 'jwt',
+    maxAge: AUTH_TOKEN_EXPIRATION_TIME,
+  },
+  jwt: {
+    maxAge: AUTH_TOKEN_EXPIRATION_TIME,
+  },
+  pages: {
+    signIn: '/signin',
+  },
+} satisfies NextAuthOptions;
diff --git a/src/lib/error.ts b/src/lib/error.ts
index 6940333b..c6005a51 100644
--- a/src/lib/error.ts
+++ b/src/lib/error.ts
@@ -6,6 +6,7 @@ export type ErrorResponseType = {
   message: string;
   code: number;
   status: false;
+  error?: any;
 };
 class ErrorHandler extends Error {
   status: false;
@@ -27,6 +28,7 @@ function standardizeApiError(error: unknown): ErrorResponseType {
       message: error.message,
       code: error.code,
       status: false,
+      error: error.error,
     };
   }
   if (error instanceof ZodError) {
diff --git a/src/lib/sendConfirmationEmail.ts b/src/lib/sendConfirmationEmail.ts
new file mode 100644
index 00000000..9819b39f
--- /dev/null
+++ b/src/lib/sendConfirmationEmail.ts
@@ -0,0 +1,43 @@
+import { TokenType } from '@prisma/client';
+import nodemailer from 'nodemailer';
+import { serverEnv } from '../env/server';
+
+export async function sendConfirmationEmail(
+  email: string,
+  confirmationLink: string,
+  type: TokenType
+) {
+  try {
+    const transporter = nodemailer.createTransport({
+      service: 'Gmail',
+      auth: {
+        user: serverEnv.EMAIL_USER,
+        pass: serverEnv.EMAIL_PASSWORD,
+      },
+    });
+
+    if (type === 'EMAIL_VERIFICATION') {
+      const mailOptions = {
+        from: serverEnv.BASE_URL,
+        to: email,
+        subject: 'Confirm your Email',
+        text: `Click the following link to confirm your email: ${confirmationLink}`,
+        html: `<p>Click the following link to confirm your email:</p><a href="${confirmationLink}">Confirm Email</a>`,
+      };
+
+      await transporter.sendMail(mailOptions);
+    } else if (type === 'RESET_PASSWORD') {
+      const mailOptions = {
+        from: serverEnv.BASE_URL,
+        to: email,
+        subject: 'Reset your password',
+        text: `Click the following link to reset your password: ${confirmationLink}`,
+        html: `<p>Click the following link to reset your password:</p><a href="${confirmationLink}">Reset Password</a>`,
+      };
+
+      await transporter.sendMail(mailOptions);
+    }
+  } catch (error) {
+    console.error('Error sending email:', error);
+  }
+}
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 01b0d83e..27e10b3d 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -1,3 +1,4 @@
+import { EMAIL_VERIFICATION_LINK_EXPIRATION_TIME } from '@/config/auth.config';
 import { type ClassValue, clsx } from 'clsx';
 import { twMerge } from 'tailwind-merge';
 
@@ -19,3 +20,11 @@ export const formatSalary = (salary: number) => {
   }
   return salary;
 };
+
+export const isTokenExpiredUtil = (createdAt: Date) => {
+  const now = new Date().getTime();
+  const tokenCreationTime = new Date(createdAt).getTime();
+  return (
+    now - tokenCreationTime > EMAIL_VERIFICATION_LINK_EXPIRATION_TIME * 1000
+  );
+};