import { prisma } from "@planarchy/db"; import NextAuth, { type NextAuthConfig } from "next-auth"; import Credentials from "next-auth/providers/credentials"; import { verify } from "@node-rs/argon2"; import { z } from "zod"; const LoginSchema = z.object({ email: z.string().email(), password: z.string().min(1), }); const authConfig = { providers: [ Credentials({ name: "credentials", credentials: { email: { label: "Email", type: "email" }, password: { label: "Password", type: "password" }, }, async authorize(credentials) { const parsed = LoginSchema.safeParse(credentials); if (!parsed.success) return null; const { email, password } = parsed.data; const user = await prisma.user.findUnique({ where: { email } }); if (!user?.passwordHash) return null; const isValid = await verify(user.passwordHash, password); if (!isValid) return null; // Track last login time await prisma.user.update({ where: { id: user.id }, data: { lastLoginAt: new Date() }, }); return { id: user.id, email: user.email, name: user.name, role: user.systemRole, }; }, }), ], callbacks: { async session({ session, token }) { if (token.sub) { session.user.id = token.sub; } if (token.role) { (session.user as typeof session.user & { role: string }).role = token.role as string; } return session; }, async jwt({ token, user }) { if (user) { token.role = (user as typeof user & { role: string }).role; } return token; }, }, pages: { signIn: "/auth/signin", }, session: { strategy: "jwt", }, } satisfies NextAuthConfig; export const { handlers, auth } = NextAuth(authConfig);