129 lines
3.7 KiB
TypeScript
129 lines
3.7 KiB
TypeScript
import NextAuth from "next-auth"
|
|
import Google from "next-auth/providers/google"
|
|
import { PrismaAdapter } from "@auth/prisma-adapter"
|
|
import { db } from "@/lib/db"
|
|
import type { Adapter } from "next-auth/adapters"
|
|
import Nodemailer from "next-auth/providers/nodemailer"
|
|
|
|
export const { auth, handlers, signIn, signOut } = NextAuth({
|
|
adapter: PrismaAdapter(db) as Adapter,
|
|
providers: [
|
|
Google({
|
|
clientId: process.env.GOOGLE_CLIENT_ID!,
|
|
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
|
|
allowDangerousEmailAccountLinking: true,
|
|
}),
|
|
Nodemailer({
|
|
server: {
|
|
host: process.env.SMTP_HOST,
|
|
port: Number(process.env.SMTP_PORT),
|
|
auth: {
|
|
user: process.env.SMTP_USER,
|
|
pass: process.env.SMTP_PASS,
|
|
},
|
|
},
|
|
from: process.env.SMTP_FROM,
|
|
}),
|
|
],
|
|
pages: {
|
|
signIn: "/auth/signin",
|
|
error: "/auth/error",
|
|
},
|
|
events: {
|
|
async linkAccount({ user, account, profile }) {
|
|
if (profile?.email && user.id) {
|
|
await db.user.update({
|
|
where: { id: user.id },
|
|
data: {
|
|
email: profile.email,
|
|
name: profile.name || user.name,
|
|
image: (profile as any)?.picture || user.image,
|
|
emailVerified: (profile as any)?.email_verified ? new Date() : null,
|
|
},
|
|
})
|
|
}
|
|
},
|
|
},
|
|
callbacks: {
|
|
async signIn({ user, account, profile, email, credentials }) {
|
|
if (!user.email) return false
|
|
|
|
if (account?.provider === "nodemailer") {
|
|
return true
|
|
}
|
|
|
|
if (account?.provider === "google" && user.email) {
|
|
const existingUser = await db.user.findUnique({
|
|
where: { email: user.email },
|
|
include: { accounts: true },
|
|
})
|
|
|
|
if (existingUser) {
|
|
const hasGoogleAccount = existingUser.accounts.some(
|
|
acc => acc.provider === "google"
|
|
)
|
|
|
|
if (!hasGoogleAccount) {
|
|
await db.account.create({
|
|
data: {
|
|
userId: existingUser.id,
|
|
type: account.type,
|
|
provider: account.provider,
|
|
providerAccountId: account.providerAccountId,
|
|
refresh_token: account.refresh_token as string | null,
|
|
access_token: account.access_token as string | null,
|
|
expires_at: account.expires_at,
|
|
token_type: account.token_type,
|
|
scope: account.scope,
|
|
id_token: account.id_token as string | null,
|
|
session_state: account.session_state as string | null,
|
|
},
|
|
})
|
|
|
|
await db.user.update({
|
|
where: { id: existingUser.id },
|
|
data: {
|
|
name: profile?.name || existingUser.name,
|
|
image: (profile as any)?.picture || existingUser.image,
|
|
emailVerified: (profile as any)?.email_verified ? new Date() : existingUser.emailVerified,
|
|
},
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
return true
|
|
},
|
|
async session({ token, session }) {
|
|
if (token) {
|
|
session.user.id = token.id as string
|
|
session.user.name = token.name as string
|
|
session.user.email = token.email as string
|
|
session.user.image = token.picture as string
|
|
}
|
|
|
|
return session
|
|
},
|
|
async jwt({ user, token }) {
|
|
const dbUser = await db.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,
|
|
picture: dbUser.image,
|
|
}
|
|
},
|
|
},
|
|
})
|