Refactor login action

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

View File

@ -1,70 +1,89 @@
"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. * This function validates a user's credentials (email and password), checks against the database,
* * and on successful validation, redirects the user to the dashboard and sets a cookie with a JWT token.
* @param email - The email of the user to validate. * If the validation fails at any stage, it throws a custom AuthError.
* @param password - The password to validate against the user's stored hash. *
* @returns The authenticated user object. * @param prevState - The previous state of the application, not currently used.
* @throws {AuthError} - EMAIL_NOT_FOUND if no user is found, INVALID_CREDENTIALS if the password doesn't match, or other auth-related errors. * @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
try { //TODO: Add validation check if the user is already logged in
const formData = { try {
email: rawFormData.get("email") as string, const formData = {
password: rawFormData.get("password") as string email: rawFormData.get("email") 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
const isMatch = await comparePassword(formData.password, user.passwordHash);
if (!isMatch) throw new AuthError(AuthErrorCode.INVALID_CREDENTIALS, 401);
//Set cookie // Compare the provided password with the user's stored password hash
//TODO: Auth: Add expiry const isMatch = await comparePassword(
const token = createJwtToken({id: user.id}); formData.password,
user.passwordHash
);
if (!isMatch) throw new AuthError(AuthErrorCode.INVALID_CREDENTIALS);
cookies().set("token",token); //Set cookie
//TODO: Auth: Add expiry
const token = createJwtToken({ id: user.id });
redirect("/dashboard"); cookies().set("token", token);
} catch (e: unknown){ redirect("/dashboard");
if (e instanceof AuthError){ } catch (e: unknown) {
if ([ // Custom error handling for authentication errors
AuthErrorCode.EMAIL_NOT_FOUND, AuthErrorCode.INVALID_CREDENTIALS if (e instanceof AuthError) {
]) { // Specific error handling for known authentication errors
return { switch (e.errorCode) {
errors: { case AuthErrorCode.EMAIL_NOT_FOUND:
message: "Email/Password combination is not match. Please try again" case AuthErrorCode.INVALID_CREDENTIALS:
} return {
} errors: {
} message:
} "Email/Password combination is incorrect. Please try again.",
},
};
default:
// Handle other types of authentication errors
return {
errors: {
message: e.message,
},
};
}
}
return { // Generic error handling for unexpected server errors
errors: { return {
message: "There's something wrong happened on the server. Please try again or contact administrator" errors: {
} message:
} "An unexpected error occurred on the server. Please try again or contact the administrator.",
} },
};
}
} }