Setting up authentication in Next.js using NextAuth.js is a great choice, especially for integrating with social providers like Facebook, Google, LinkedIn, etc., and handling forgot and reset password flows. Let’s walk through a detailed guide covering setup, social provider integration, password management, and debugging tips.

Prerequisites

Before starting, make sure you have:

  • Node.js and npm installed.
  • A Next.js project set up (npm init next-app if starting from scratch).
  • Basic understanding of JavaScript and React.

Step 1: Install NextAuth.js

First, install NextAuth.js and necessary packages:

npm install next-auth

Step 2: Setup NextAuth.js Configuration

Create a pages/api/auth/[...nextauth].js file for NextAuth.js configuration:

// pages/api/auth/[...nextauth].js
import NextAuth from 'next-auth';
import Providers from 'next-auth/providers';

export default NextAuth({
  // Configure one or more authentication providers
  providers: [
    Providers.Google({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    }),
    Providers.Facebook({
      clientId: process.env.FACEBOOK_CLIENT_ID,
      clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
    }),
    Providers.LinkedIn({
      clientId: process.env.LINKEDIN_CLIENT_ID,
      clientSecret: process.env.LINKEDIN_CLIENT_SECRET,
    }),
    // Add other providers as needed
  ],

  // Optional SQL or MongoDB database to persist users
  // database: process.env.DATABASE_URL,

  // Optional custom JWT token encryption secret for extra security
  // secret: process.env.AUTH_SECRET,

  // Configure other NextAuth.js options as needed
});

This is the basic setup for Google, Facebook, and LinkedIn providers. Ensure to replace process.env variables with actual credentials securely stored in your environment.

NextAuth provides many more functionalities over it. Let’s explore few of them:-

The profile function in the provided below code snippet can be used for providers in the NextAuth.js configuration. It’s a callback function that allows you to customize the user object returned by the respective provider.

GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID as string,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
      profile(profile: GoogleProfile) {
        return {
          ...profile,
          id: profile.email.toString(),
          image: profile.avatar_url,
        };
      },
    }),

Takes an argument: The argument received by the function is the original profile object returned by the chosen provider (either GoogleProfile or any other providers). This object contains various user details retrieved during the authentication process.

  • It spreads the original profile object (...profile) to ensure all existing properties are retained.
  • Then, it modifies specific properties you might need:
  • id: Sets the user ID to their email address converted to a string. This ensures a unique identifier within your application.
  • image: Sets the user’s profile picture URL (extracted from avatar_url in both cases).

Additionally, there are callbacks like jwt and session also introduced customized token handling and session management.

Explanation:-

The jwt callback is used to modify the JSON Web Token (JWT) before it’s stored or sent to the client. Here, it checks if a user object exists and adds the user’s ID (user.id) to the token. This allows the token to carry additional user information securely.

async jwt({ token, user }) {
  if (user) {
    token.id = user.id; // Store user ID in token
  }
  return token;
}

The session callback is responsible for setting up the session object. It attaches the user ID (token.id) to the session, ensuring that session data is populated with necessary user details across requests.

async session({ session, token }) {
  session.user.id = token.id; // Attach user ID to session
  return session;
}

These callbacks enhance the functionality of NextAuth.js by integrating user identification and session management seamlessly into the authentication flow. They ensure that authenticated sessions can access user-specific data securely and efficiently.

Step 3: Create Signin and Callback Pages

Next, create pages/signin.js for the sign-in page and pages/api/auth/callback/[provider].js for callback handling. Example for Google sign-in:

// pages/signin.js
import { signIn } from 'next-auth/react';

export default function SignIn() {
  return (
    <div>
      <button onClick={() => signIn('google')}>Sign in with Google</button>
      {/* Add more signin options */}
    </div>
  );
}



// pages/api/auth/callback/google.js
import { handleCallback } from 'next-auth/react';

export default async function callback(req, res) {
  await handleCallback(req, res, { debug: true });
}

Step 4: Forgot Password and Reset Password

For forgot and reset password functionality, extend NextAuth.js with email providers and custom callbacks:

// Update pages/api/auth/[...nextauth].js
export default NextAuth({
  providers: [
    // Existing providers
    Providers.Email({
      server: {
        host: process.env.EMAIL_SERVER_HOST,
        port: process.env.EMAIL_SERVER_PORT,
        auth: {
          user: process.env.EMAIL_SERVER_USER,
          pass: process.env.EMAIL_SERVER_PASSWORD,
        },
      },
      from: process.env.EMAIL_FROM,
    }),
  ],

  pages: {
    forgotPassword: '/auth/forgot-password',
    resetPassword: '/auth/reset-password',
  },

  callbacks: {
    async sendVerificationRequest({ identifier, url, token, provider }) {
      // Custom logic to send email with verification link
    },
    async resetPassword({ token, email, newPassword }) {
      // Custom logic to reset password
    },
  },
});

Step 5: Debugging NextAuth.js

To debug NextAuth.js:

  1. Enable debug mode by passing { debug: true } to handleCallback() or in configuration.
  2. Check server logs (npm run dev or npm run start outputs server logs).
  3. Use browser developer tools for client-side issues.
  4. Verify environment variables and provider configurations.

Final Notes

  • Environment Variables: Store sensitive data like CLIENT_IDCLIENT_SECRET, and DATABASE_URL in .env.local and load them using process.env.
  • Security: Use HTTPS in production and set strong secrets and keys.

This guide should help you get started with comprehensive authentication in Next.js using NextAuth.js. It covers sign-in, social logins, password management, and debugging techniques.

You may also like

Leave a Reply