import NextAuth from "next-auth"; import Credentials from "next-auth/providers/credentials"; import { DrizzleAdapter } from "@auth/drizzle-adapter"; import bcrypt from "bcryptjs"; import { eq } from "drizzle-orm"; import { db } from "@/db"; import { users, authAccounts, sessions, verificationTokens, } from "@/db/schema"; import { authConfig } from "@/auth.config"; export const { handlers, signIn, signOut, auth } = NextAuth({ ...authConfig, adapter: DrizzleAdapter(db, { usersTable: users, accountsTable: authAccounts, sessionsTable: sessions, verificationTokensTable: verificationTokens, }), session: { strategy: "jwt" }, providers: [ Credentials({ name: "Credentials", credentials: { email: { label: "Email", type: "email" }, password: { label: "Password", type: "password" }, }, authorize: async (credentials) => { const email = String(credentials?.email ?? "").toLowerCase().trim(); const password = String(credentials?.password ?? ""); if (!email || !password) return null; const [u] = await db.select().from(users).where(eq(users.email, email)); if (!u || !u.passwordHash) return null; const ok = await bcrypt.compare(password, u.passwordHash); if (!ok) return null; return { id: u.id, email: u.email, name: u.name ?? u.email, image: u.image ?? undefined, }; }, }), ], callbacks: { ...authConfig.callbacks, async jwt({ token, user }) { if (user?.id) token.userId = user.id; if (token.userId) { const [u] = await db .select({ householdId: users.householdId, role: users.role }) .from(users) .where(eq(users.id, token.userId as string)); if (u) { token.householdId = u.householdId ?? null; token.role = u.role; } } return token; }, async session({ session, token }) { if (session.user) { session.user.id = token.userId as string; (session.user as { householdId?: string | null }).householdId = (token.householdId as string | null) ?? null; (session.user as { role?: string }).role = (token.role as string) ?? "member"; } return session; }, }, });