finance-calculator/auth.ts
2025-06-14 21:04:23 +08:00

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,
}
},
},
})