diff options
Diffstat (limited to 'src/lib/auth.ts')
| -rw-r--r-- | src/lib/auth.ts | 21 |
1 files changed, 19 insertions, 2 deletions
diff --git a/src/lib/auth.ts b/src/lib/auth.ts index 0ed9d12..ad47d5f 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -1,6 +1,7 @@ import { type NextAuthOptions } from "next-auth" import CredentialsProvider from "next-auth/providers/credentials" import bcrypt from "bcryptjs" +import { authenticator } from "otplib" import dbConnect from "./mongodb" import User from "@/model/User" import { loginSchema } from "./validation" @@ -11,7 +12,8 @@ export const authOptions: NextAuthOptions = { name: "credentials", credentials: { email: { label: "Email", type: "email" }, - password: { label: "Password", type: "password" } + password: { label: "Password", type: "password" }, + twoFactorCode: { label: "2FA Code", type: "text" } }, async authorize(credentials) { if (!credentials?.email || !credentials?.password) return null @@ -19,7 +21,7 @@ export const authOptions: NextAuthOptions = { const result = loginSchema.safeParse(credentials) if (!result.success) return null - const { email, password } = result.data + const { email, password, twoFactorCode } = result.data try { await dbConnect() @@ -30,6 +32,17 @@ export const authOptions: NextAuthOptions = { const isPasswordValid = await bcrypt.compare(password, user.password) if (!isPasswordValid) return null + if (user.twoFactorEnabled) { + if (!twoFactorCode) { + throw new Error("2FA_REQUIRED") + } + + const isValid = authenticator.check(twoFactorCode, user.twoFactorSecret) + if (!isValid) { + throw new Error("Invalid 2FA Code") + } + } + return { id: user._id.toString(), email: user.email, @@ -38,6 +51,10 @@ export const authOptions: NextAuthOptions = { } } catch (error) { console.error("Auth error:", error) + // Rethrow specific 2FA errors so they reach the client + if (error instanceof Error && (error.message === "2FA_REQUIRED" || error.message === "Invalid 2FA Code")) { + throw error + } return null } } |
