I’m learning authentication for remix. I’m creating a signup sheet where the user creates an account with an email, username, and password. I can create the account on my database but the authentication fails. Here’s my code. I would appreciate any insight or help you can give me.
import React, { useState } from "react";
import type { MetaFunction } from "@remix-run/node";
import { ActionFunction, json, LoaderFunction } from "@remix-run/node";
import { useActionData, Link } from "@remix-run/react";
import { getMeta } from "~/utils/meta";
import { authenticator } from "~/.server/auth";
import { createUser } from "~/.server/user";
import Layout from "~/components/Layout";
import Textfield from "~/components/TextField";
import MaxWidthWrapper from "~/components/MaxWidthWrapper";
export const meta: MetaFunction = () => {
const meta = getMeta({ title: "Pirate Radio Network" });
return meta;
};
export const loader: LoaderFunction = async ({ request }) => {
const user = await authenticator.isAuthenticated(request, {
successRedirect: "/",
});
return { user };
};
export const action: ActionFunction = async ({ request }) => {
const form = await request.formData();
const action = form.get("_action");
const email = form.get("email");
const password = form.get("password");
const username = form.get("username");
if (
typeof action !== "string" ||
typeof email !== "string" ||
typeof password !== "string" ||
typeof username !== "string"
) {
return json({ error: `Invalid Form Data`, form: action }, { status: 400 });
}
console.log(`Type of action: ${typeof action}`);
console.log(`Type of email: ${typeof email}`);
console.log(`Type of password: ${typeof password}`);
console.log(`Type of username: ${typeof username}`);
await createUser({ email, password, username })
.then(() => console.log("User created successfully"))
.catch((error) => console.error("User creation failed:", error));
// Clone the request
const clonedRequest = new Request(request, {
body: form,
});
console.log(`Email: ${email}`);
console.log(`Username: ${username}`);
return await authenticator
.authenticate("form", clonedRequest, {
successRedirect: "/",
failureRedirect: "/join",
context: {formData: form},
})
.then(() => {
console.log("Authentication succeeded");
return json({ status: "success" }); // Add a return statement here
})
.catch((error) => {
console.error("Authentication failed:", error);
console.error("Request:", clonedRequest);
return json({ error: "Authentication failed" }, { status: 400 }); // Add a return statement here
});
};
export default function Signup() {
const actionData = useActionData() as { context?: { formData: any } };
const formData = actionData?.context?.formData || {};
const [formState, setFormState] = useState({
email: formData.email || "",
password: formData.password || "",
username: formData.username || "",
});
// Updates the form data when an input changes
const handleInputChange = (
event: React.ChangeEvent<HTMLInputElement>,
field: string
) => {
setFormState((form) => ({ ...form, [field]: event.target.value }));
};
Here is my auth sever code.
import { Authenticator, AuthorizationError } from "remix-auth";
import { sessionStorage } from "./session";
import { FormStrategy } from "remix-auth-form";
import { prisma } from "./db";
import bcrypt from "bcryptjs";
import { Role } from "@prisma/client";
interface User {
id: string;
email: string;
username: string;
firstName: string;
lastName: string;
createdAt: Date;
updatedAt: Date;
role: Role;
password: string;
}
const sessionSecret = process.env.SESSION_SECRET;
if (!sessionSecret) {
throw new Error("SESSION_SECRET must be set");
}
const authenticator = new Authenticator<any>(sessionStorage);
const formStrategy = new FormStrategy(async ({form}) => {
const email = form.get("email") as string;
const password = form.get("password") as string;
const username = form.get("username") as string;
if (!email || !password || !username) {
console.log("Form data is missing");
throw new AuthorizationError();
}
const user = await prisma.user.findFirst({
where: {
OR: [
{ email: email },
{ username: username },
],
},
select: {
id: true,
email: true,
username: true,
firstName: true,
lastName: true,
createdAt: true,
updatedAt: true,
role: true,
password: true,
},
}) as unknown as User;
if (!user) {
console.log("Invalid email or username");
throw new AuthorizationError();
}
const passwordsMatch = await bcrypt.compare(password, user.password as string);
if (!passwordsMatch) {
throw new AuthorizationError();
}
return user;
});
authenticator.use(formStrategy, "form");
export {authenticator};
I expected the user account to authenticate upon creation.