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.