DEV Community

Cover image for Unlock Next-Level Authentication in Next.js with Next Auth and TypeScript Module Augmentation
Joseph Mukorivo
Joseph Mukorivo

Posted on • Originally published at josemukorivo.com

Unlock Next-Level Authentication in Next.js with Next Auth and TypeScript Module Augmentation

Next.js is a popular React framework for building web applications. When building authentication features in Next.js, developers often use NextAuth.js as it provides a simple way to implement authentication, authorization and session management. NextAuth.js supports a variety of authentication providers such as Google, Facebook, Twitter, etc.

In some cases, developers may want to extend the functionality of the User and Session objects provided by NextAuth.js. Fortunately, TypeScript module augmentation allows us to do just that.

TypeScript module augmentation is a way of extending the types of an existing module. In our case, we will be using module augmentation to add additional fields to the User and Session objects provided by NextAuth.js.

Step 1: Create a custom User and Session interface

You'll need to create a custom interface for your User and Session objects. This will allow you to add additional fields to the objects using TypeScript module augmentation.

Create a new file in the root of your project called next-auth.d.ts. This file will contain the custom User and Session interfaces. Add the following code to the file:

import NextAuth from "next-auth"

declare module "next-auth" {
  interface User {
    name: string
  }

  interface Session {
    user: {
      name: string
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

In this example, we're adding a name field to both the User and Session objects. You can add any additional fields that you need.

Step 2: Update your authentication provider

Now that you've defined your custom User and Session interfaces, you'll need to update your authentication provider to include the new fields.

In your [...nextauth].ts file, add the following code to the options object:

import NextAuth from 'next-auth';
import type { NextAuthOptions } from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
import { signIn } from '@/services/auth';

const MINUTE = 60;
const HOUR = 60 * MINUTE;

export const authOptions: NextAuthOptions = {
  providers: [
    CredentialsProvider({
      credentials: {},
      async authorize(credentials, req) {
        const { email, password, tenant } = credentials as {
          email: string;
          password: string;
        };
        const { user, token, error } = await signIn(
          { email, password }
        );
        if (user) {
          return {
            id: +user.id,
            name:
              `${user.firstName} ${user.lastName}`,
            email: user.email,
            jwt: token,
          };
        }
        if (error) {
          throw new Error(error);
        }
        return null;
      },
    }),
  ],
  jwt: {
    secret: process.env.NEXTAUTH_SECRET,
  },
  session: {
    maxAge: 8 * HOUR, // 8 hours
  },
  pages: {
    signIn: '/login',
  },
  callbacks: {
    async jwt({ token, user }) {
      if (user) {
        token.id = +user.id;
        token.jwt = user.jwt;
        token.name = user.name;
        token.email = user.email;
      }
      return token;
    },
    session: async ({ session, token }) => {
      session.user.id = token.id;
      session.jwt = token.jwt;
      session.user.name = token.name;
      session.user.email = token.email;
      return session;
    },
  },
};

export default NextAuth(authOptions);
Enter fullscreen mode Exit fullscreen mode

In this example, we're adding a callbacks object to the options object. This object includes a session function that is called when a new session is created. In the session function, we're adding the name field to the user object in the session.

Step 3: Use the custom fields in your application

Now that you've added the custom fields to your User and Session objects, you can use them in your application. Here's an example of how to use the name field in a React component:

import { useSession } from "next-auth/react"

export default function Home() {
  const { data: session } = useSession()

  return (
    <div>
      <h1>Welcome, {session?.user.name ?? "guest"}!</h1>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

In this example, we're using the useSession hook to get the user's session object.The code displays a greeting that includes the user's name if they are logged in, or "guest" if they are not. The ?. operator is used to safely access the name property of the user object within the session object. If session is undefined or user is undefined, the ?? operator provides a fallback value of "guest".

Top comments (1)

Collapse
 
sergeyleschev profile image
Sergey Leschev • Edited

I agree that NextAuth.js is an excellent choice for implementing authentication features in Next.js applications. Moreover, extending the functionality of User and Session objects using TypeScript module augmentation is a great way to unlock next-level authentication. We have used this technique as well, and it has worked smoothly for us.