import NextAuth from 'next-auth' import { UserRole } from '@prisma/client' import { PrismaAdapter } from '@auth/prisma-adapter' import { db } from '@/lib/db' import authConfig from '@/auth.config' import { getUserById } from '@/data/user' import { AUTH_ERROR_URL, AUTH_LOGIN_URL } from '@/config/routes' declare module 'next-auth' { interface Session { user: { role: UserRole } } } export const VERIFICATION_TOKEN_EXPIRATION_DURATION = 3_600_000 export const { handlers: { GET, POST }, auth, signIn, signOut, } = NextAuth({ pages: { signIn: AUTH_LOGIN_URL, error: AUTH_ERROR_URL, }, events: { async linkAccount ({ user }) { await db.user.update({ where: { id: user.id as string }, data: { emailVerified: new Date() }, }) }, }, callbacks: { async signIn ({ user, account }) { // Bypass email verification when Oauth are being used if (account?.provider !== 'credentials') return true const existingUser = await getUserById(user.id as string) // Prevent sign in without email verification if (!existingUser?.emailVerified) return false // TODO: Add 2FA check return true }, async session ({ token, session }) { if (token.sub && session.user) { session.user.id = token.sub } if (token.role && session.user) { session.user.role = token.role as UserRole } return session }, async jwt ({ token }) { if (!token.sub) return token const existingUser = await getUserById(token.sub) if (!existingUser) return token token.role = existingUser.role return token }, }, adapter: PrismaAdapter(db), session: { strategy: 'jwt' }, ...authConfig, })