Next Auth Azure App Service 500 on production only

47 Views Asked by At

I am hosting a Nextjs application using Next Auth on Azure App Services. AzureADProvider and EmailProvider are both used.

In my azure app service hosted development slot, both AzureADProvider and EmailProvider are working just fine.

Only in the production slot EmailProvider is giving a 500 Internal Server Error. AzureADProvider is still working as expected.

I have a NEXTAUTH_SECRET set as well as a NEXTAUTH_URL pointing at the each slot's respective URL.

Here is the code for the page that is giving me a 500 on prod only:

import React, { useState } from 'react';
import { getSession, getProviders } from 'next-auth/react';
import { NextPage } from 'next';
import { useRouter } from 'next/dist/client/router';
import { VerificationStep } from '../../components/auth/VerificationStep';
import { EmailInput } from '../../components/auth/EmailInput';
import { isDev, redirectUrl } from '../../utils/envConfig';

interface Provider {
  id: string;
  name: string;
  type: string;
  [k: string]: string;
}

interface SigninPageProps {
  isLoggedIn: boolean;
  providers: Array<Provider>;
  csrfToken: string;
}

const SigninPage: NextPage<SigninPageProps> = ({ providers, isLoggedIn }) => {
  const { query, push } = useRouter();
  const { error } = query;
  const callbackUrl = isDev ? 'http://localhost:3000' : redirectUrl;

  const [email, setEmail] = useState('');
  const [showVerificationStep, setShowVerificationStep] = useState(false);
  const emailProvider = Object.values(providers).filter(
    (provider) => provider.type === 'email'
  );

  console.log(providers)

  const handleBackButtonClick = () => {
    push('/');
  };

  if (showVerificationStep) {
    return (
      <main className='flex min-h-screen flex-col items-center pt-8'>
        <div className='w-full pl-8'>
          <button onClick={handleBackButtonClick}>Back to Home</button>
        </div>
        <VerificationStep email={email} callbackUrl={callbackUrl} />
      </main>
    );
  }

  return (
    <main className='flex min-h-screen flex-col items-center pt-8'>
      <div className='w-full pl-8'>
        <button onClick={handleBackButtonClick}>Back to Home</button>
      </div>

      <div className='flex w-1/2 flex-col items-center p-4 sm:w-64'>
        <h1 className='p-2 text-xl font-bold'>Volunteer sign in:</h1>
        <p className='text-center'>
          Enter email address to receive verification code.
        </p>
        {emailProvider.map((provider) => (
          <EmailInput
            key={provider.id}
            provider={provider}
            onSuccess={(email) => {
              setEmail(email);
              setShowVerificationStep(true);
            }}
          />
        ))}
      </div>
    </main>
  );
};

SigninPage.getInitialProps = async (context) => {
  const { req } = context;
  const session = await getSession({ req });
  return {
    isLoggedIn: session !== null,
    providers: await getProviders(),
  } as unknown as SigninPageProps;
};

export default SigninPage;

When I look at the log streams after I see this error I see

2024-03-10T21:43:40.3927007Z TypeError: Cannot read properties of null (reading 'useReducer')
2024-03-10T21:43:40.3941673Z     at exports.useReducer (/node_modules/[4mreact[24m/cjs/react.production.min.js:25:274)
2024-03-10T21:43:40.3954186Z     at C [90m(file:///home/site/wwwroot/[39mnode_modules/[4mreact-toastify[24m/dist/react-toastify.esm.mjs:2:4007[90m)[39m
2024-03-10T21:43:40.4023821Z     at [90mfile:///home/site/wwwroot/[39mnode_modules/[4mreact-toastify[24m/dist/react-toastify.esm.mjs:2:12379
2024-03-10T21:43:40.4100971Z     at Wc [90m(/home/site/wwwroot/[39mnode_modules/[4mreact-dom[24m/cjs/react-dom-server.browser.production.min.js:68:44[90m)[39m
2024-03-10T21:43:40.4313158Z     at Zc [90m(/home/site/wwwroot/[39mnode_modules/[4mreact-dom[24m/cjs/react-dom-server.browser.production.min.js:73:362[90m)[39m
2024-03-10T21:43:40.4396418Z     at Z [90m(/home/site/wwwroot/[39mnode_modules/[4mreact-dom[24m/cjs/react-dom-server.browser.production.min.js:76:89[90m)[39m
2024-03-10T21:43:40.4404593Z     at $c [90m(/home/site/wwwroot/[39mnode_modules/[4mreact-dom[24m/cjs/react-dom-server.browser.production.min.js:78:98[90m)[39m
2024-03-10T21:43:40.4414742Z     at bd [90m(/home/site/wwwroot/[39mnode_modules/[4mreact-dom[24m/cjs/react-dom-server.browser.production.min.js:77:404[90m)[39m
2024-03-10T21:43:40.4425460Z     at Z [90m(/home/site/wwwroot/[39mnode_modules/[4mreact-dom[24m/cjs/react-dom-server.browser.production.min.js:76:217[90m)[39m
2024-03-10T21:43:40.4489477Z     at Zc [90m(/home/site/wwwroot/[39mnode_modules/[4mreact-dom[24m/cjs/react-dom-server.browser.production.min.js:74:209[90m)[39m

nextauth config:

import NextAuth from 'next-auth';
import AzureADProvider from 'next-auth/providers/azure-ad';
import EmailProvider from 'next-auth/providers/email';
import { MongoDBAdapter } from '@auth/mongodb-adapter';
import SequelizeAdapter from '@next-auth/sequelize-adapter';
import sequelize from '../../../../DB/sequelize';
import db from '../../../../DB/Models';

const nodemailer = require('nodemailer');

const generateAuthtoken = async () => {
  const min = 10000; // Minimum 5-digit number
  const max = 99999; // Maximum 5-digit number
  const token = Math.floor(Math.random() * (max - min + 1)) + min;
  return token;
};

export const authOptions = {
  //!SECTION - SEQUELIZE
  adapter: SequelizeAdapter(sequelize, {
    models: {
      User: db.User,
      Account: db.Account,
      Session: db.Session,
      // VerificationRequest: db.VerificationRequest,
      VerificationToken: db.VerificationToken
    },
  }),

  secret: process.env.NEXTAUTH_SECRET,
  providers: [
    AzureADProvider({
      clientId: process.env.NEXT_PUBLIC_AZURE_AD_CLIENT_ID,
      clientSecret: process.env.NEXT_PUBLIC_AZURE_AD_CLIENT_SECRET,
      tenantId: process.env.NEXT_PUBLIC_AZURE_AD_TENANT_ID,
      profile(profile) {
        return {
          id: profile.sub,
          role: 'employee',
          email: profile.email,
          name: profile.name,
        };
      },
      allowDangerousEmailAccountLinking: true,
    }),
    EmailProvider({
      server: process.env.NEXT_PUBLIC_EMAIL_SERVER,
      from: process.env.NEXT_PUBLIC_EMAIL_FROM,
      maxAge: 5 * 60,
      generateVerificationToken: async () => {
        const token = await generateAuthtoken();
        return token;
      },
      sendVerificationRequest: ({
        identifier: email,
        url,
        token,
        baseUrl,
        provider,
      }) => {
        return new Promise((resolve, reject) => {
          const { server, from } = provider;
          // Strip protocol from URL and use domain as site name
          const emailContent = `
          <div style="text-align: center;">
            <h1 style="font-size: 24px; font-weight: bold;">Your code to log in to unity-trail.catholiccharities.net is:</h1>
            <p style="font-size: 36px; font-weight: bold;">${token}</p>
          </div>
        `;

          nodemailer.createTransport(server).sendMail(
            {
              to: email,
              from,
              subject: `Catholic Charities Authentication code: ${token}`,
              html: emailContent,
            },
            (error) => {
              if (error) {
                logger.error('SEND_VERIFICATION_EMAIL_ERROR', email, error);
                console.error('SEND_VERIFICATION_EMAIL_ERROR', email, error);
                return reject(
                  new Error(`SEND_VERIFICATION_EMAIL_ERROR ${error}`)
                );
              }
              return resolve();
            }
          );
        });
      },
    }),
  ],
  callbacks: {
    async session({ session, user }) {
      session.user.id = user.id;
      session.user.role = user.role;
      session.user.email = user.email;
      session.user.name = user.name;
      return session;
    },
  },
  session: {
    maxAge: 43200, // 12 hours
  },
  pages: {
    signIn: '/auth/signin',
  },
};

export default NextAuth(authOptions);

I have tried checking my env vars to ensure that I'm setting it up correctly. I expect to see a signin page where the user can enter their email address. If the user's email exists in the db, a code is sent to their email and they can proceed with login.

0

There are 0 best solutions below