import { env } from "@/env.mjs" import { db } from "@/lib/db" import { PrismaAdapter } from "@auth/prisma-adapter" import { compare } from "bcrypt" import { NextAuthOptions } from "next-auth" import { Adapter } from "next-auth/adapters" import CredentialsProvider from 'next-auth/providers/credentials' import GitHubProvider from "next-auth/providers/github" import { normalize } from "normalize-diacritics" export const authOptions: NextAuthOptions = { adapter: PrismaAdapter(db as any) as Adapter, session: { strategy: 'jwt' }, pages: { signIn: "/login", }, providers: [ GitHubProvider({ clientId: env.GITHUB_CLIENT_ID, clientSecret: env.GITHUB_CLIENT_SECRET, }), CredentialsProvider({ name: 'Login', credentials: { usernameOrEmail: { label: 'Username or Email', type: 'text' }, password: { label: 'Password', type: 'password' } }, async authorize(credentials) { if (!credentials?.usernameOrEmail || !credentials?.password) { return null } const user = await db.user.findFirst({ where: { OR: [ { username: credentials.usernameOrEmail.toLowerCase() }, { email: credentials.usernameOrEmail.toLowerCase() }, ], }, }); if (!user || !user.password) { throw new Error('user not found') } const isPasswordValid = await compare( credentials.password, user.password ) if (!isPasswordValid) { throw new Error('invalid password') } return { id: user.id, username: user.username, email: user.email, } } }) ], secret: env.NEXTAUTH_SECRET, callbacks: { async signIn({ user, account }) { if (account?.provider === 'github') { const { name, email } = user; if (!name || !email) { return false; } let username = await normalize(name.toLowerCase().replace(/\s/g, '')); let isUnique = false; while (!isUnique) { const existingUserName = await db.user.findFirst({ where: { username, NOT: { email }, }, }) if (existingUserName) { username = `${username}${Math.floor(Math.random() * 1000)}` } else { isUnique = true; } } await db.user.update({ where: { email }, data: { username }, }); } return true; }, async session({ token, session }) { if (token) { session.user.id = token.id session.user.name = token.name session.user.username = token.username session.user.email = token.email session.user.image = token.picture } return session }, async jwt({ token, user }) { 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, username: dbUser.username, email: dbUser.email, picture: dbUser.image, } } } }