UNPKG

create-auth-js-boiler

Version:
284 lines (258 loc) 7.33 kB
"use server"; import { registerSchemaType, registerSchema, loginSchema, loginSchemaType, forgotPasswordSchema, forgotPasswordSchemaType, newPasswordSchema, newPasswordSchemaType, } from "@/schemas/auth.schema"; import { signIn } from "@/auth"; import bcrypt from "bcryptjs"; import { prisma } from "@/lib/prisma"; import { AuthError } from "next-auth"; import { generateVerificationToken, generatePasswordResetToken, generateTwoFactorToken, } from "@/lib/tokens"; import { sendVerificationEmail, sendPasswordResetEmail, sendTwoFactorTokenEmail, } from "@/lib/mail"; import { getVerificationTokenByToken } from "@/lib/verification-token"; import { getPasswordResetTokenByToken } from "@/lib/passwordResetToken"; import { getTwoFactorTokenByEmail } from "@/lib/two-factor-token"; import { getTwoFactorConfirmationByUserId } from "@/lib/two-factor-confirmation"; export const googleSignIn = async () => { await signIn("google"); }; export const register = async (values: registerSchemaType) => { const validatedFields = registerSchema.safeParse(values); if (!validatedFields.success) { return { error: "Invalid fields!" }; } const { email, name, password } = validatedFields.data; const hashedPassword = await bcrypt.hash(password, 10); const user = await prisma.user.findUnique({ where: { email, }, }); if (user) { return { error: "Something went wrong" }; } await prisma.user.create({ data: { email, name, password: hashedPassword, }, }); const verificationToken = await generateVerificationToken(email); await sendVerificationEmail(verificationToken.email, verificationToken.token); return { success: "Confirmation email sent!" }; }; export const login = async (values: loginSchemaType) => { const validatedFields = loginSchema.safeParse(values); if (!validatedFields.success) { return { error: "Invalid fields!" }; } const { email, password, code } = validatedFields.data; const existingUser = await prisma.user.findUnique({ where: { email, }, }); if (!existingUser || !existingUser.password || !existingUser.email) { return { error: "Invalid credentials!" }; } const passwordMatch = await bcrypt.compare(password, existingUser.password); if (!passwordMatch) { return { error: "Invalid credentials!" }; } if (!existingUser.emailVerified) { const verificationToken = await generateVerificationToken( existingUser.email, ); await sendVerificationEmail( verificationToken.email, verificationToken.token, ); return { success: "Confirmation email sent!", redirectUrl: "/auth/login", }; } if (existingUser.isTwoFactorEnabled && existingUser.email) { if (code) { const twoFactorToken = await getTwoFactorTokenByEmail(existingUser.email); if (!twoFactorToken) { return { error: "Invalid two factor token!" }; } if (twoFactorToken.token !== code) { return { error: "Invalid two factor token!" }; } const hasExpired = new Date(twoFactorToken.expires) < new Date(); if (hasExpired) { return { error: "Token expired!" }; } await prisma.twoFactorToken.delete({ where: { id: twoFactorToken.id, }, }); const existingConfirmation = await getTwoFactorConfirmationByUserId( existingUser.id, ); if (existingConfirmation) { await prisma.twoFactorConfirmation.delete({ where: { id: existingConfirmation.id, }, }); } await prisma.twoFactorConfirmation.create({ data: { userId: existingUser.id, }, }); } else { const twoFactorToken = await generateTwoFactorToken(existingUser.email); await sendTwoFactorTokenEmail(twoFactorToken.email, twoFactorToken.token); return { twoFactor: true, }; } } try { await signIn("credentials", { email, password, redirect: false, }); } catch (error) { if (error instanceof AuthError) { switch (error.type) { case "CredentialsSignin": return { error: "Invalid credentials!" }; default: return { error: "Something went wrong!" }; } } throw error; } let redirectUrl; if (existingUser.role == "MODERATOR") { redirectUrl = "/moderator"; } else if (existingUser.role == "ADMIN") { redirectUrl = "/admin"; } else if (existingUser.role == "USER") { redirectUrl = "/"; } return { success: "Logged in successfully!", redirectUrl: redirectUrl, // Include the redirect URL }; }; export const newVerification = async (token: string) => { const existingToken = await getVerificationTokenByToken(token); if (!existingToken) { return { error: "Invalid token!" }; } const hasExpired = new Date(existingToken.expires) < new Date(); if (hasExpired) { return { error: "Token expired!" }; } const existingUser = await prisma.user.findUnique({ where: { email: existingToken.email, }, }); if (!existingUser) { return { error: "Something went wrong!" }; } await prisma.user.update({ where: { id: existingUser.id, }, data: { emailVerified: new Date(), email: existingToken.email, }, }); await prisma.verificationToken.delete({ where: { id: existingToken.id, }, }); return { success: "Email verified successfully!" }; }; export const forgotPassword = async (values: forgotPasswordSchemaType) => { const validatedFields = forgotPasswordSchema.safeParse(values); if (!validatedFields.success) { return { error: "Invalid fields!" }; } const { email } = validatedFields.data; const existingUser = await prisma.user.findUnique({ where: { email, }, }); if (!existingUser) { return { error: "Something went wrong!" }; } const passwordResetToken = await generatePasswordResetToken(email); await sendPasswordResetEmail( passwordResetToken.email, passwordResetToken.token, ); return { success: "Reset email sent!" }; }; export const newPassword = async ( values: newPasswordSchemaType, token?: string, ) => { if (!token) { return { error: "Missing token!" }; } const validatedFields = newPasswordSchema.safeParse(values); if (!validatedFields.success) { return { error: "Invalid fields!" }; } const { password } = validatedFields.data; const existingToken = await getPasswordResetTokenByToken(token); if (!existingToken) { return { error: "Invalid token!" }; } const hasExpired = new Date(existingToken.expires) < new Date(); if (hasExpired) { return { error: "Token expired!" }; } const existingUser = await prisma.user.findUnique({ where: { email: existingToken.email, }, }); if (!existingUser) { return { error: "Something went wrong!" }; } const hashedPassword = await bcrypt.hash(password, 10); await prisma.user.update({ where: { id: existingUser.id, }, data: { password: hashedPassword, }, }); await prisma.passwordResetToken.delete({ where: { id: existingToken.id, }, }); return { success: "Password updated successfully!" }; };