Refactor login action

This commit is contained in:
Sianida26 2024-01-15 01:53:20 +07:00
parent d05fa7e27d
commit 3e1fea085c

View File

@ -1,44 +1,52 @@
"use server" "use server";
import prisma from "@/db"; import prisma from "@/db";
import { User } from "@prisma/client"; import { User } from "@prisma/client";
import AuthError, { AuthErrorCode } from "../AuthError"; import AuthError, { AuthErrorCode } from "../AuthError";
import { comparePassword, createJwtToken } from "../authUtils"; import { comparePassword, createJwtToken } from "../authUtils";
import { cookies } from "next/headers"; import { cookies } from "next/headers";
import { redirect } from 'next/navigation'; import { redirect } from "next/navigation";
/** /**
* Validates the user by their email and password. * Handles the sign-in process for a user.
* If the user is found and the password is correct, it returns the user.
* Throws an AuthError if any authentication step fails.
* *
* @param email - The email of the user to validate. * This function validates a user's credentials (email and password), checks against the database,
* @param password - The password to validate against the user's stored hash. * and on successful validation, redirects the user to the dashboard and sets a cookie with a JWT token.
* @returns The authenticated user object. * If the validation fails at any stage, it throws a custom AuthError.
* @throws {AuthError} - EMAIL_NOT_FOUND if no user is found, INVALID_CREDENTIALS if the password doesn't match, or other auth-related errors. *
* @param prevState - The previous state of the application, not currently used.
* @param rawFormData - The raw form data containing the user's email and password.
* @returns A promise that resolves to a redirect to the dashboard on successful authentication,
* or an object containing error details on failure.
* @throws {AuthError} - Specific authentication error based on the failure stage.
*/ */
export default async function signIn(prevState: any, rawFormData: FormData) { export default async function signIn(prevState: any, rawFormData: FormData) {
//TODO: Add Throttling //TODO: Add Throttling
//TODO: Add validation check if the user is already logged in
try { try {
const formData = { const formData = {
email: rawFormData.get("email") as string, email: rawFormData.get("email") as string,
password: rawFormData.get("password") as string password: rawFormData.get("password") as string,
} };
// Retrieve user from the database by email // Retrieve user from the database by email
const user = await prisma.user.findUnique({ const user = await prisma.user.findUnique({
where: { email: formData.email } where: { email: formData.email },
}); });
// Throw if user not found // Throw if user not found
if (!user) throw new AuthError(AuthErrorCode.EMAIL_NOT_FOUND, 401); if (!user) throw new AuthError(AuthErrorCode.EMAIL_NOT_FOUND);
// Throw if user has no password hash // Throw if user has no password hash
// TODO: Add check if the user uses another provider // TODO: Add check if the user uses another provider
if (!user.passwordHash) throw new AuthError(AuthErrorCode.EMPTY_USER_HASH, 500); if (!user.passwordHash)
throw new AuthError(AuthErrorCode.EMPTY_USER_HASH);
// Compare the provided password with the user's stored password hash // Compare the provided password with the user's stored password hash
const isMatch = await comparePassword(formData.password, user.passwordHash); const isMatch = await comparePassword(
if (!isMatch) throw new AuthError(AuthErrorCode.INVALID_CREDENTIALS, 401); formData.password,
user.passwordHash
);
if (!isMatch) throw new AuthError(AuthErrorCode.INVALID_CREDENTIALS);
//Set cookie //Set cookie
//TODO: Auth: Add expiry //TODO: Auth: Add expiry
@ -47,24 +55,35 @@ export default async function signIn(prevState: any, rawFormData: FormData) {
cookies().set("token", token); cookies().set("token", token);
redirect("/dashboard"); redirect("/dashboard");
} catch (e: unknown) { } catch (e: unknown) {
// Custom error handling for authentication errors
if (e instanceof AuthError) { if (e instanceof AuthError) {
if ([ // Specific error handling for known authentication errors
AuthErrorCode.EMAIL_NOT_FOUND, AuthErrorCode.INVALID_CREDENTIALS switch (e.errorCode) {
]) { case AuthErrorCode.EMAIL_NOT_FOUND:
case AuthErrorCode.INVALID_CREDENTIALS:
return { return {
errors: { errors: {
message: "Email/Password combination is not match. Please try again" message:
} "Email/Password combination is incorrect. Please try again.",
} },
};
default:
// Handle other types of authentication errors
return {
errors: {
message: e.message,
},
};
} }
} }
// Generic error handling for unexpected server errors
return { return {
errors: { errors: {
message: "There's something wrong happened on the server. Please try again or contact administrator" message:
} "An unexpected error occurred on the server. Please try again or contact the administrator.",
} },
};
} }
} }