When I am trying to do next build to prepare my application for production, the next build script always stuck at collect page data, with the following error:
TypeError: o is not a function
#13 89.81 at 17692 (.next/server/app/api/(myapi)/route.js:1:xxx)
Opening up the .next file will show its breaking at the following expression:
let u = [
o({
name: "Credentials",
credentials: {
email: { label: "Email", type: "email" },
password: { label: "Password", type: "password" },
},
I am using nextjs with App Router, reading NextAuth seems has very little document on v4 for App Router and on v5 document does not even exist, this is super confusing and I got totally stuck, wondering if there is anyone can offer help?
My code:
app/api/auth/[...nextauth]/route.js:
import NextAuth from "next-auth";
import { authOptions } from "@/lib/auth/options";
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
lib/auth/options.js:
import { PrismaAdapter } from "@next-auth/prisma-adapter";
import prisma from "@/lib/prisma";
import { getProviders } from "./providers";
import { callbacks } from "./callbacks";
export const authOptions = {
adapter: PrismaAdapter(prisma),
providers: getProviders(),
callbacks,
pages: {
signIn: "/sign_in",
signUp: "/sign_up",
verifyRequest: "/verify-email",
},
session: {
strategy: "jwt",
},
secret: process.env.NEXTAUTH_SECRET,
debug: process.env.NODE_ENV !== "production",
};
lib/auth/providers.js:
import CredentialsProvider from "next-auth/providers/credentials";
import GoogleProvider from "next-auth/providers/google";
import prisma from "@/lib/prisma";
import bcrypt from "bcrypt";
export const getProviders = () => {
const providers = [
CredentialsProvider({
name: "Credentials",
credentials: {
email: { label: "Email", type: "email" },
password: { label: "Password", type: "password" },
},
async authorize(credentials) {
try {
if (!credentials?.email || !credentials?.password) {
throw new Error("allFieldsRequired");
}
const user = await prisma.user.findUnique({
where: { email: credentials.email },
});
if (!user || !user.password) {
throw new Error("invalidCredentials");
}
const isValid = await bcrypt.compare(credentials.password, user.password);
if (!isValid) {
throw new Error("invalidCredentials");
}
if (!user.emailVerified) {
throw new Error("emailNotVerified");
}
return { id: user.id, name: user.name, email: user.email, accessToken: user.accessToken };
} catch (error) {
console.error("Authorize error:", error.message);
throw error;
}
},
}),
];
if (
process.env.GOOGLE_CLIENT_ID &&
process.env.GOOGLE_CLIENT_SECRET &&
process.env.NEXT_PUBLIC_ENABLE_GOOGLE_LOGIN !== "false"
) {
providers.push(
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
authorization: {
params: {
scope: "openid email profile https://www.googleapis.com/auth/calendar",
},
},
})
);
}
return providers;
};
lib/auth/callbacks.js:
import prisma from "@/lib/prisma";
export const callbacks = {
async signIn({ user, account }) {
try {
if (account.provider === "google") {
await prisma.user.upsert({
where: { email: user.email },
update: {
accessToken: account.access_token,
emailVerified: user.emailVerified || new Date(),
},
create: {
email: user.email,
name: user.name,
googleId: account.providerAccountId,
accessToken: account.access_token,
emailVerified: new Date(),
},
});
}
return true;
} catch (error) {
console.error("SignIn callback error:", error);
return false;
}
},
async jwt({ token, user }) {
if (user) {
token.id = user.id;
token.accessToken = user.accessToken;
token.name = user.name;
token.email = user.email;
}
return token;
},
async session({ session, token }) {
try {
session.user.id = token.id;
session.user.accessToken = token.accessToken;
session.user.name = token.name;
session.user.email = token.email;
return session;
} catch (error) {
console.error("Session callback error:", error);
throw error;
}
},
};
In my API calls when I need to secure the call:
import { getServerSession } from 'next-auth/next';
import { authOptions } from '@/lib/auth/options';
import prisma from '@/lib/prisma.js';
import { NextResponse } from 'next/server';
export async function GET(req) {
try {
const session = await getServerSession(authOptions);
if (!session || !session.user || !session.user.id) {
...
It's very plain boilerplate code that works fine in npm run dev but breaks when build npm run build