Auth

This configuration is used to handle user authentication in a Next.js application. It allows users to log in using their email and password and maintains their session using JWT tokens. The configuration ensures secure password handling using bcrypt and integrates with MongoDB for user data storage.

NextAuth Configuration for User Authentication


import User from "@/models/User";
import db from "@/utils/db";
import NextAuth from "next-auth/next";
let bcrypt = require('bcryptjs');
import  CredentialsProvider  from "next-auth/providers/credentials";

export default NextAuth({
    session: {
        strategy:'jwt',
    },
    callbacks: {
        async jwt({ token, user }) {
            if(user?._id) token._id = user._id;
            if(user?.isAdmin) token.isAdmin = user.isAdmin
            return token;
        },
        async session({session, token}){
            if(token?._id) session.user._id = token._id;
            if(token?.isAdmin) session.user.isAdmin = token.isAdmin
            return session;
        },
    },
    providers:[
        CredentialsProvider({
            async authorize(credentials) {
                await db.connect();
                const user = await User.findOne({
                    email: credentials.email,
                });
                await db.disconnect();
                if(user && bcrypt.compareSync(credentials.password, user.password)){
                    return {
                        _id: user._id,
                        name: user.name,
                        email: user.email,
                        image: 'f',
                        isAdmin: user.isAdmin,
                    };
                }
                throw new Error('Invalid email or password');
              }
           }),
        ],
      })
    

This code configures NextAuth for handling user authentication in a Next.js application. It uses a custom credentials provider to authenticate users with email and password and manages sessions using JSON Web Tokens (JWT). It also integrates MongoDB for user data storage and bcrypt for password hashing.

Import Statements

  1. - User: Imports the User model to interact with the users collection in MongoDB.
  2. - db: Imports database utility functions for connecting and disconnecting from MongoDB.
  3. - NextAuth: Imports the NextAuth library for authentication.
  4. - bcrypt: Imports bcryptjs for hashing and comparing passwords.
  5. - CredentialsProvider: Imports the credentials provider from NextAuth for custom authentication.

NextAuth Configuration

  1. - session.strategy: Specifies the strategy for session handling, which is set to 'jwt' (JSON Web Token).
  2. - callbacks: Defines callback functions to control JWT and session behavior.

Callbacks

  1. - jwt : A callback that modifies the JWT token. It adds the user's _id and isAdmin :properties to the token if they exist.
  2. - session: A callback that modifies the session object. It adds the user's _id and isAdmin properties to the session if they exist.

Providers

  1. - authorize: An asynchronous function that:
  2. 1. Connects to the database.
  3. 2. Searches for a user with the provided email.
  4. 3. Disconnects from the database.
  5. 4. Compares the provided password with the stored hashed password using bcrypt.
  6. 5. Returns a user object if authentication is successful.
  7. 6. Throws an error if authentication fails.

Custom App Component with Authentication


import { NextComponentType } from 'next'
import { SessionProvider, useSession } from 'next-auth/react'
import type { AppProps } from 'next/app'
import { useRouter } from 'next/router'
type CustomAppProps = AppProps & {
  Component: NextComponentType & {auth?: {adminOnly:boolean}} // add auth type
  adminOnly:boolean
}

interface AuthProps{
  children:any;
  adminOnly: boolean
}

export default function App({ Component, pageProps:{session, ...pageProps} }: CustomAppProps) {
  return (
    <>
    <SessionProvider session={session}>
    {Component.auth ? (
        <Auth adminOnly={Component.auth.adminOnly}>
          <div >
            <Component {...pageProps} />
          </div>
        </Auth>
      ):(
        <div>
          <Component {...pageProps} />
        </div>
      )}
     </SessionProvider>
   </>
  )
}


function Auth({ children, adminOnly }:AuthProps){
  const router = useRouter();
  const {status, data: session}:any = useSession({
    required: true,
    onUnauthenticated(){
      router.push('/unauthorized?message=login required');
    }
  });
  if(status === 'loading'){
    return <div>Loading...</div>
  }

  if (adminOnly && !session.user.isAdmin){
    router.push('/unauthorized?message=admin login required');
  }

  return children;
}
    

This code sets up a custom App component for a Next.js application that integrates NextAuth for session management and authentication. It ensures that certain pages are only accessible to authenticated users, and optionally, only to admin users.

Import Statements

  1. - NextComponentType: TypeScript type for Next.js components.
  2. - SessionProvider, useSession: Imports from next-auth/react to manage session state and access session data.
  3. - AppProps: TypeScript type for Next.js App properties.
  4. - useRouter: Hook from next/router to handle client-side navigation.

Custom Type Definitions

  1. - CustomAppProps: Extends AppProps to include auth property in components, which is an object containing adminOnly boolean.
  2. - AuthProps: Defines the type for the Auth component props.

Component: App

  1. - SessionProvider: Wraps the entire application to provide session context.
  2. - Conditional Rendering::
  3. - If the Component has an auth property, it wraps the component with the Auth component.
  4. - If the Component does not have an auth property, it renders the component directly.

Component: Auth

  1. - useRouter: Used to navigate the user based on authentication status.
  2. - useSession:: Retrieves session data and the status of the session.
  3. - required: true has an auth property, it wraps the component with the Auth component.
  4. - onUnauthenticated Redirects unauthenticated users to the unauthorized/ page with a message.

Conditional Rendering:

  1. - If the session status is loading, it displays a loading message.
  2. - If adminOnly is true and the authenticated user is not an admin, it redirects to the /unauthorized page with a message.
  3. - If the user meets all requirements, it renders the children components.