React Router v7 Integration

I want to add auth in react router v7 app, the better-auth docs only mention the integration for Remix, so i tried using that but it didnt work im new to react router / remix and dont know how to make it work the below method mentioned in remix integration docs gives 405 error on form submission // POST http://localhost:5173/api/auth/sign-up/email 405 (Method Not Allowed)
const signUp = async () => {
await authClient.signUp.email(
{
email,
password,
name,
},
{
onRequest: () => {
console.warn("Sign up Initiated...");
},
onSuccess: () => {
alert("Successfully signed up!");
},
onError: (ctx) => {
alert(ctx.error);
},
}
);
};
const signUp = async () => {
await authClient.signUp.email(
{
email,
password,
name,
},
{
onRequest: () => {
console.warn("Sign up Initiated...");
},
onSuccess: () => {
alert("Successfully signed up!");
},
onError: (ctx) => {
alert(ctx.error);
},
}
);
};
7 Replies
Dev
DevOP3w ago
so i tried using the action function, which also didn't work // POST http://localhost:5173/auth/register.data 400 (Bad Request)
export async function action({ request }: Route.ActionArgs) {
const formData = await request.formData();
const email = formData.get("email") as string;
const name = formData.get("name") as string;
const password = formData.get("password") as string;

try {
await authClient.signUp.email(
{ email, password, name },
{
onRequest: () => {
console.warn("Sign up Initiated...");
},
onSuccess: () => {
console.log("Successfully signed up!");
},
onError: (ctx) => {
throw new Error(ctx.error.message);
},
}
);
} catch (error: any) {
return new Response(JSON.stringify({ error: error.message }), {
status: 400,
headers: { "Content-Type": "application/json" },
});
}
}
export async function action({ request }: Route.ActionArgs) {
const formData = await request.formData();
const email = formData.get("email") as string;
const name = formData.get("name") as string;
const password = formData.get("password") as string;

try {
await authClient.signUp.email(
{ email, password, name },
{
onRequest: () => {
console.warn("Sign up Initiated...");
},
onSuccess: () => {
console.log("Successfully signed up!");
},
onError: (ctx) => {
throw new Error(ctx.error.message);
},
}
);
} catch (error: any) {
return new Response(JSON.stringify({ error: error.message }), {
status: 400,
headers: { "Content-Type": "application/json" },
});
}
}
im not sure im doing it right or wrong
lonelyplanet
lonelyplanet3w ago
Whats your auth.ts look like and where have you implemented your handler?
Dev
DevOP3w ago
>app/lib/auth.ts
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@/db/drizzle";
import { openAPI } from "better-auth/plugins";

export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg",
}),
emailAndPassword: {
enabled: true,
},
plugins: [openAPI()],
secret: process.env.BETTER_AUTH_SECRET!,
});
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@/db/drizzle";
import { openAPI } from "better-auth/plugins";

export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg",
}),
emailAndPassword: {
enabled: true,
},
plugins: [openAPI()],
secret: process.env.BETTER_AUTH_SECRET!,
});
>app/routes/api.auth.$.ts
import { auth } from "@/lib/auth";
import type { LoaderFunctionArgs, ActionFunctionArgs } from "react-router";

export async function loader({ request }: LoaderFunctionArgs) {
return auth.handler(request);
}

export async function action({ request }: ActionFunctionArgs) {
return auth.handler(request);
}
import { auth } from "@/lib/auth";
import type { LoaderFunctionArgs, ActionFunctionArgs } from "react-router";

export async function loader({ request }: LoaderFunctionArgs) {
return auth.handler(request);
}

export async function action({ request }: ActionFunctionArgs) {
return auth.handler(request);
}
>app/lib/auth-client.ts
import { createAuthClient } from "better-auth/react";

export const authClient = createAuthClient({
baseURL: import.meta.env.BETTER_AUTH_URL!,
});
import { createAuthClient } from "better-auth/react";

export const authClient = createAuthClient({
baseURL: import.meta.env.BETTER_AUTH_URL!,
});
Unknown User
Unknown User3w ago
Message Not Public
Sign In & Join Server To View
Dev
DevOP3w ago
this works but not as expected, its signing up the user if i use the onSubmit in the page itself (the nextjs way), ideally it should work with the action function, which it does not also, after the user is signed up, and i try to log in using the same methodology as signup, the "page" shows "Error - Method not allowed", with empty console logs, but the onSuccess method gets triggered and i get the alert of "sign up successful", but then session is null in the app, but in the cookies i can see the better-auth.session_token okay now im not getting the method not allowed error but its still not signing me in this is how im doing it
export async function loader() {
const { data: session } = await authClient.getSession();
console.log("session: ", session);
return session;
}

export default function Home() {
const session = useLoaderData<typeof loader>();
return (
<div className="p-5">
<div>
<span>
{session ? (
<> Signed in as {session.user.name}
</>
) : (
"Not signed in"
)}
</span>
</div>
</div>
);
}
export async function loader() {
const { data: session } = await authClient.getSession();
console.log("session: ", session);
return session;
}

export default function Home() {
const session = useLoaderData<typeof loader>();
return (
<div className="p-5">
<div>
<span>
{session ? (
<> Signed in as {session.user.name}
</>
) : (
"Not signed in"
)}
</span>
</div>
</div>
);
}
Unknown User
Unknown User3w ago
Message Not Public
Sign In & Join Server To View
Dev
DevOP3w ago
Thanks Phillex, this worked, ill keep that in mind, Also, for anyone new, react-router framework specific docs will be appreciated

Did you find this page helpful?