import NextAuth, { type DefaultSession } from "next-auth"; import Credentials from "next-auth/providers/credentials"; import { z } from "zod"; import { ACTIVATE_STATUSES } from "@/lib/constants"; const credentialsSchema = z.object({ adminName: z.string().trim().min(1), password: z.string().min(1), }); type AdminAuthRow = { AdminID: bigint | number; Name: string; Email: string; AccountType: bigint | number; ActivateStatus: bigint | number; }; declare module "next-auth" { interface Session { user: { adminID: number; accountType: number; activateStatus: number; } & DefaultSession["user"]; } interface User { accountType: number; activateStatus: number; } } declare module "next-auth/jwt" { interface JWT { accountType?: number; activateStatus?: number; } } export const { handlers: { GET, POST }, auth, signIn, signOut, } = NextAuth({ pages: { signIn: "/login", }, session: { strategy: "jwt", }, providers: [ Credentials({ credentials: { adminName: { label: "관리자 아이디", type: "text" }, password: { label: "암호", type: "password" }, }, async authorize(credentials) { const parsedCredentials = credentialsSchema.safeParse(credentials); if (!parsedCredentials.success) { return null; } const { db } = await import("@/lib/db"); const { adminName, password } = parsedCredentials.data; const admins = await db.$queryRaw` SELECT AdminID, Name, Email, AccountType, ActivateStatus FROM admin WHERE Name = ${adminName} AND Password = PASSWORD(${password}) LIMIT 1 `; const admin = admins[0]; const adminID = Number(admin?.AdminID); const accountType = Number(admin?.AccountType); const activateStatus = Number(admin?.ActivateStatus); if (!admin || activateStatus === ACTIVATE_STATUSES.PENDING) { return null; } return { id: String(adminID), name: admin.Name, email: admin.Email, accountType, activateStatus, }; }, }), ], callbacks: { jwt({ token, user }) { if (user) { token.accountType = user.accountType; token.activateStatus = user.activateStatus; } return token; }, session({ session, token }) { return { ...session, user: { ...session.user, adminID: Number(token.sub), accountType: Number(token.accountType), activateStatus: Number(token.activateStatus), }, }; }, }, });