Help in Nextauth EmailProvider

I am getting this strange error in emailProvider for nextauth. Does anyone know what I am doing wrong?
Type 'EmailConfig' is not assignable to type 'Provider'.
Type 'EmailConfig' is not assignable to type 'EmailConfig & InternalProviderOptions'.
Type 'EmailConfig' is not assignable to type 'InternalProviderOptions'.
Types of property 'options' are incompatible.
Type 'EmailUserConfig' is not assignable to type 'Record<string, unknown>'.
Index signature for type 'string' is missing in type 'EmailUserConfig'.ts(2322)
Type 'EmailConfig' is not assignable to type 'Provider'.
Type 'EmailConfig' is not assignable to type 'EmailConfig & InternalProviderOptions'.
Type 'EmailConfig' is not assignable to type 'InternalProviderOptions'.
Types of property 'options' are incompatible.
Type 'EmailUserConfig' is not assignable to type 'Record<string, unknown>'.
Index signature for type 'string' is missing in type 'EmailUserConfig'.ts(2322)
7 Replies
GBianchi
GBianchi10mo ago
Here's my full code:
import type { DefaultSession } from "@auth/core/types";
import { PrismaAdapter } from "@auth/prisma-adapter";
import NextAuth from "next-auth";
import EmailProvider from "next-auth/providers/email";
import GoogleProvider from "next-auth/providers/google";

import { prisma } from "@kdx/db";

import { env } from "./env.mjs";

export type { Session } from "next-auth";

// Update this whenever adding new providers so that the client can
export const providers = ["google", "email"] as const;
export type OAuthProviders = (typeof providers)[number];

declare module "next-auth" {
interface Session {
user: {
id: string;
// ...other properties
// role: UserRole;
activeWorkspaceId: string; // Might need fix
activeWorkspaceName: string;
} & DefaultSession["user"];
}

interface User {
activeWorkspaceId?: string | null;
}
}

export const {
handlers: { GET, POST },
auth,
CSRF_experimental,
} = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
GoogleProvider({
clientId: env.GOOGLE_CLIENT_ID,
clientSecret: env.GOOGLE_CLIENT_SECRET,
}),
EmailProvider({
server: {
host: env.EMAIL_SERVER_HOST,
port: env.EMAIL_SERVER_PORT,
auth: {
user: env.EMAIL_SERVER_USER,
pass: env.EMAIL_SERVER_PASSWORD,
},
},
from: env.EMAIL_FROM,
type: "email",
sendVerificationRequest: () => {
throw new Error("Not implemented");
},
id: "",
name: "",
}),
],
},
secret: env.NEXTAUTH_SECRET,
pages: {
signIn: "/auth/signIn",
//signOut: '/auth/signout',
//error: '/auth/error', // Error code passed in query string as ?error=
//verifyRequest: '/auth/verify-request', // (used for check email message)
//newUser: "/auth/new-user"
},
});
import type { DefaultSession } from "@auth/core/types";
import { PrismaAdapter } from "@auth/prisma-adapter";
import NextAuth from "next-auth";
import EmailProvider from "next-auth/providers/email";
import GoogleProvider from "next-auth/providers/google";

import { prisma } from "@kdx/db";

import { env } from "./env.mjs";

export type { Session } from "next-auth";

// Update this whenever adding new providers so that the client can
export const providers = ["google", "email"] as const;
export type OAuthProviders = (typeof providers)[number];

declare module "next-auth" {
interface Session {
user: {
id: string;
// ...other properties
// role: UserRole;
activeWorkspaceId: string; // Might need fix
activeWorkspaceName: string;
} & DefaultSession["user"];
}

interface User {
activeWorkspaceId?: string | null;
}
}

export const {
handlers: { GET, POST },
auth,
CSRF_experimental,
} = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
GoogleProvider({
clientId: env.GOOGLE_CLIENT_ID,
clientSecret: env.GOOGLE_CLIENT_SECRET,
}),
EmailProvider({
server: {
host: env.EMAIL_SERVER_HOST,
port: env.EMAIL_SERVER_PORT,
auth: {
user: env.EMAIL_SERVER_USER,
pass: env.EMAIL_SERVER_PASSWORD,
},
},
from: env.EMAIL_FROM,
type: "email",
sendVerificationRequest: () => {
throw new Error("Not implemented");
},
id: "",
name: "",
}),
],
},
secret: env.NEXTAUTH_SECRET,
pages: {
signIn: "/auth/signIn",
//signOut: '/auth/signout',
//error: '/auth/error', // Error code passed in query string as ?error=
//verifyRequest: '/auth/verify-request', // (used for check email message)
//newUser: "/auth/new-user"
},
});
GBianchi
GBianchi10mo ago
No description
Alan Ibarra-2310
Alan Ibarra-231010mo ago
Here is how I implemented it. My email provider looks practically identical.
import NextAuth from "next-auth";
import type { NextAuthOptions } from "next-auth";
import GitHubProvider from "next-auth/providers/github";
import EmailProvider from "next-auth/providers/email";
import { prisma } from "@/db";
import { PrismaAdapter } from "@next-auth/prisma-adapter";
import { verificationRequest } from "../VerificationRequest";
export const authOptions: NextAuthOptions = {
adapter: PrismaAdapter(prisma),
session: {
strategy: "jwt",
},
providers: [
GitHubProvider({
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
}),
EmailProvider({
server: {
host: process.env.EMAIL_SERVER_HOST,
port: +(process.env.EMAIL_SERVER_PORT as string),
auth: {
user: process.env.EMAIL_SERVER_USER,
pass: process.env.EMAIL_SERVER_PASSWORD,
},
},
from: process.env.EMAIL_FROM,

sendVerificationRequest: verificationRequest,
}),
],
import NextAuth from "next-auth";
import type { NextAuthOptions } from "next-auth";
import GitHubProvider from "next-auth/providers/github";
import EmailProvider from "next-auth/providers/email";
import { prisma } from "@/db";
import { PrismaAdapter } from "@next-auth/prisma-adapter";
import { verificationRequest } from "../VerificationRequest";
export const authOptions: NextAuthOptions = {
adapter: PrismaAdapter(prisma),
session: {
strategy: "jwt",
},
providers: [
GitHubProvider({
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
}),
EmailProvider({
server: {
host: process.env.EMAIL_SERVER_HOST,
port: +(process.env.EMAIL_SERVER_PORT as string),
auth: {
user: process.env.EMAIL_SERVER_USER,
pass: process.env.EMAIL_SERVER_PASSWORD,
},
},
from: process.env.EMAIL_FROM,

sendVerificationRequest: verificationRequest,
}),
],
callbacks: {
async signIn({ account, user }) {
if (account && account.provider === "github") {
const res = await fetch("https://api.github.com/user/public_emails", {
headers: {
Authorization: `Bearer ${account.access_token}`,
Accept: "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28",
},
});
const emails: {
primary: boolean;
email: string;
verified: boolean;
visibility: string | null;
}[] = await res.json();

if (emails.length) {
user.email = emails[0].email;
}
return true;
}
// for email credentials
return true;
},

async session({ token, session }) {
if (token) {
session.user.id = token.id;
session.user.name = token.name;
session.user.email = token.email;
session.user.image = token.image || "/user.png";
}
return session;
},
async jwt({ token, user }) {
const dbUser = await prisma.user.findFirst({
where: {
email: token.email,
},
});
if (!dbUser) {
if (user) {
token.id = user?.id;
}
return token;
}
return {
id: dbUser.id,
name: dbUser.name,
email: dbUser.email,
image: dbUser.image,
};
},
},
pages: {
signIn: "/login",
},
};
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
callbacks: {
async signIn({ account, user }) {
if (account && account.provider === "github") {
const res = await fetch("https://api.github.com/user/public_emails", {
headers: {
Authorization: `Bearer ${account.access_token}`,
Accept: "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28",
},
});
const emails: {
primary: boolean;
email: string;
verified: boolean;
visibility: string | null;
}[] = await res.json();

if (emails.length) {
user.email = emails[0].email;
}
return true;
}
// for email credentials
return true;
},

async session({ token, session }) {
if (token) {
session.user.id = token.id;
session.user.name = token.name;
session.user.email = token.email;
session.user.image = token.image || "/user.png";
}
return session;
},
async jwt({ token, user }) {
const dbUser = await prisma.user.findFirst({
where: {
email: token.email,
},
});
if (!dbUser) {
if (user) {
token.id = user?.id;
}
return token;
}
return {
id: dbUser.id,
name: dbUser.name,
email: dbUser.email,
image: dbUser.image,
};
},
},
pages: {
signIn: "/login",
},
};
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
GBianchi
GBianchi10mo ago
Yeah, I dont know. It is still not working
jonasmerlin
jonasmerlin8mo ago
@GBianchi Did you find a solution to this? Because I'm having the same problem right now.
GBianchi
GBianchi8mo ago
Hi, nope. I just completely removed email for now If you come across a solution, please let me know!
jasny
jasny7mo ago
This seems to be a typing bug in the next-auth library and not an actual problem. I ended up just overwriting the type of the options property to satisfy the Provider type: as EmailConfig & { options: Record<string, unknown> }.
export const authOptions: NextAuthOptions = {
adapter: PrismaAdapter(prisma),
session: {
strategy: "jwt",
},
providers: [
GitHubProvider({
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
}),
EmailProvider({
server: {
host: process.env.EMAIL_SERVER_HOST,
port: +(process.env.EMAIL_SERVER_PORT as string),
auth: {
user: process.env.EMAIL_SERVER_USER,
pass: process.env.EMAIL_SERVER_PASSWORD,
},
},
from: process.env.EMAIL_FROM,

sendVerificationRequest: verificationRequest,
}) as EmailConfig & { options: Record<string, unknown> },
],
export const authOptions: NextAuthOptions = {
adapter: PrismaAdapter(prisma),
session: {
strategy: "jwt",
},
providers: [
GitHubProvider({
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
}),
EmailProvider({
server: {
host: process.env.EMAIL_SERVER_HOST,
port: +(process.env.EMAIL_SERVER_PORT as string),
auth: {
user: process.env.EMAIL_SERVER_USER,
pass: process.env.EMAIL_SERVER_PASSWORD,
},
},
from: process.env.EMAIL_FROM,

sendVerificationRequest: verificationRequest,
}) as EmailConfig & { options: Record<string, unknown> },
],