NextAuth Implementation

prathmesh kaleprathmesh kale
4 min read

As the name suggest nextAuth in next.js for Authentication , Once you learn the structure which i have provided in image and understand the code it will be easy because there are not much changes you need to do , it’s authentication there is not much you can change it has it’s structure for security reasons to do so.

Lets dive into each segment .

  1. next-auth.d.ts

import {DefaultSession} from "next-auth";

declare module "next-auth" {

    interface Session{
        user: {
            id: string;
        } & DefaultSession["user"]
    }
}

This snippet tell typescript "Hey, I'm extending the session interface. My user object will include everything that NextAuth normally provides (name, email, image) plus an id field of type string.” this helps us avoiding type errors when accessing session.user.id.

  1. Registeruser.ts

 import {NextRequest, NextResponse} from "next/server";
 import {connectToDatabase}  from "@/lib/db";
 import User from "@/models/User";
     //Creating a new user
 export async function POST(request: NextRequest){
    try{
        const {email,password} = await request.json();

        if(!email || !password){
            return NextResponse.json(
                {error:"Email and password are requred"},
                {status: 400}
            );
        }
        await connectToDatabase();;
        const existingUser = await User.findOne({ email });
        if (existingUser) {
          return NextResponse.json(
            { error: "Email already registered" },
            { status: 400 }
          );
        }

        await User.create({
          email,
          password,
        });
        return NextResponse.json(
            { message: "User registered successfully" },
            { status: 201 }
          );
        } catch (error) {
          console.error("Registration error:", error);
          return NextResponse.json(
            { error: "Failed to register user" },
            { status: 500 }
          );
        }
      }

This is segement where you can register new User. This is easy compared to authroizing old user , same as we register user anywhere else.

  1. NextAuthOptions

import { NextAuthOptions } from "next-auth";
import  CredentailsProvider from "next-auth/providers/credentials"
import bcrypt from "bcryptjs";
import { connectToDatabase } from "./db";
import UserModel from "../models/User";
// Authorizing the user if it exist in db or not.
export const authOptions: NextAuthOptions ={

    providers : [
        CredentailsProvider({
            name: "Credentials",
          credentials:{
            email:{label: "Email", type: "text"},
              password: {label: "Password", type:"password"},
          },
          async authorize(credentials){
            if(!credentials?.email || !credentials?.password){
                throw new Error("Missing email or password");
            }
            try {
                await connectToDatabase();
                const user = await UserModel.findOne({email: credentials.email });

                if(!user){
                    throw new Error("No user found with this email");
                }
                const isValid = await bcrypt.compare(
                    credentials.password,
                    user.password
                );
                if (!isValid) {
                    throw new Error("Invalid password");
                  }
                  return {
                    id:user._id.toString(),
                    email:user.email,
                  };
            } catch(error){
                console.error("Auth error:", error);
                throw error;
            }
          },
        }),
    ],
    callbacks:{
        async jwt({token,user}){
            if(user){
                token.id = user.id;
            }
            return token;
        },

        async session({session,token}){
            if(session.user){
                session.user.id = token.id as string;
            }
            return session;
        },
    },
    pages: {
        signIn: "/login",
        error: "/login",
      },
      session: {
        strategy: "jwt",
        maxAge: 30 * 24 * 60 * 60,
      },
      secret: process.env.NEXTAUTH_SECRET,
};

This the most difficult part of nextAuth, there are two segments in this code first is Provider in which we ask user credenatils which in this case are email and password and after that we authorize those credentials all this happens insider the provider and then comes Callback in which we generate jwt token and give session.id for each user once this is over there is just routes which we define for this and session duration.

  1. Middleware

     import { withAuth } from "next-auth/middleware";
     import { NextResponse } from "next/server";
    
     export default withAuth(
       function middleware() {
         return NextResponse.next();
       },
       {
         callbacks: {
           authorized: ({ token, req }) => {
             const { pathname } = req.nextUrl;
    
             // Allow auth-related routes
             if (
               pathname.startsWith("/api/auth") ||
               pathname === "/login" ||
               pathname === "/register"
             ) {
               return true;
             }
    
             // Public routes
             if (pathname === "/" || pathname.startsWith("/api/videos")) {
               return true;
             }
             // All other routes require authentication
             return !!token;
           },
         },
       }
     );
    
     export const config = {
       matcher: [
         /*
          * Match all request paths except:
          * - _next/static (static files)
          * - _next/image (image optimization files)
          * - favicon.ico (favicon file)
          * - public folder
          */
         "/((?!_next/static|_next/image|favicon.ico|public/).*)",
       ],
     };
    

    It ensures that certain pages are only accessible to logged-in users. /((?!_next/static|_next/image|favicon.ico|public/). this tells middleware to which route to apply. it Apply to everything except:

    • Static files

    • Image optimizations

    • Favicon

    • /public folder assets

  1. […nextauth]

import NextAuth from "next-auth";
import { authOptions } from "@/lib/auth";

const handler = NextAuth(authOptions);

export { handler as GET, handler as POST };

This is the final glue that connects NextAuth to your Next.js API route.

Thanks for reading this blog.

1
Subscribe to my newsletter

Read articles from prathmesh kale directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

prathmesh kale
prathmesh kale