Search code examples
node.jstypescriptnodemailernext-auth

Getting the NextAuth session with EmailProvider inside getServerSideProps throws fs "module not found"


I'm trying to get the NextAuth session from a server-side call in getServerSideProps, and I'm using an EmailProvider with NextAuth. I'm following an example from NextAuth's documentation to get the session from getServerSideProps.

In the [...nextauth].ts] configuration file, I use the EmailProvider.

// pages/api/auth/[...nextauth].ts

import NextAuth from 'next-auth';
import EmailProvider from 'next-auth/providers/email';

export const authOptions = {
  adapter: PrismaAdapter(prisma),
  providers: [
    EmailProvider({ ... }),
  ],
};

export default NextAuth(authOptions);

In a frontend component, I attempt to get the session like this:

// components/MyComponent.tsx

import { authOptions } from '@auth/[...nextauth]';

export const getServerSideProps = async ({ req, res }) => {
  const serverSession = await getServerSession(req, res, authOptions);
  
  return {
    props: { serverSession },
  };
};

I even added webpack configs in next.config.js to ignore server-only code when on the client:

// next.config.js
module.exports = {
  webpack: (config, { isServer, webpack }) => {
    if (!isServer) {
      config.plugins.push(
        new webpack.IgnorePlugin({ resourceRegExp: /^\/pages\/api\/auth\/$/ })
      );
    }
  }
}

The problem is that when I add import { authOptions } from '@auth/[...nextauth]'; to my frontend component file, it throws a compilation error:

// compilation error
error - ./node_modules/nodemailer/lib/dkim/index.js:10:0
Module not found: Can't resolve 'fs'

https://nextjs.org/docs/messages/module-not-found

Import trace for requested module:
./node_modules/nodemailer/lib/mailer/index.js
./node_modules/nodemailer/lib/nodemailer.js
./node_modules/next-auth/providers/email.js
./pages/api/auth/[...nextauth].ts
./components/MyComponent.tsx
./pages/index.tsx

I guess this is expected behavior when I import [...nextauth] in MyComponent, it imports EmailProvider, which imports nodemailer, and nodemailer imports fs. Since MyComponent runs on the client, it throws an error, because fs module is not available on the client.

So I've tried a few things:

  • add "fs": false to my package.json (source here) This works as a bandaid solution, but then more modules need to get added to package.json, and I go down a rabbit hole that eventually prevents prisma from being used.
  • Import authOptions inside getServerSideProps (example). This did not affect the error.

Any other ideas? Thank you!


Solution

  • Ah so components can't do server-side rendering (SSR), only pages can. Here's more documentation.

    So to fix this, I moved getServerSideProps to a page (e.g. pages/index.tsx or any other page in the root of pages/). The code looks the same, which is copied below, but the file that the code lives in is different.

    // components/MyComponent.tsx <-- this is wrong
    // ^^ IT SHOULD NOT BE A COMPONENT
    
    // pages/index.tsx <-- or whatever page you're using
    // ^^ IT SHOULD BE A PAGE INSTEAD OF A COMPONENT
    
    import { authOptions } from '@auth/[...nextauth]';
    
    export const getServerSideProps = async ({ req, res }) => {
      const serverSession = await getServerSession(req, res, authOptions);
      
      return {
        props: { serverSession },
      };
    };