CORS "preflight response did not succeed" issue

Hello, I’m having an issue with Better-Auth when using simple routes like /sign-up/email. Whether I use the authClient or a fetch call, the browser reports a CORS error (see screenshot). I can successfully call my Elysia API without any problems. If I use Postman or Scalar, the request works correctly. I’m confident that my Better-Auth (client and server) and Elysia configurations are correct. Stack : Bun 1.2.14 better-auth 1.2.8 better-fetch 1.1.2 elysiajs 1.3.0 Better-auth server config
// ./app/server/src/libs/auth.ts
export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg",
schema: schema,
}),
appName: "MySuperApp",
trustedOrigins: [env.CORS_ORIGIN], // http://localhost:8000
emailAndPassword: {
enabled: true,
autoSignInAfterVerification: false,
},

/* Plugins configuration */
plugins: [
openAPI(),
organization(),
phoneNumber({
// ...
emailOTP({
// ...
}),
],

/* Better-auth schema change */
user: {
additionalFields: {
first_name: {
type: "string",
required: true,
},
onboarding: {
type: "string",
required: true,
},
},
},

/* Advenced configuration */
advanced: {
cookiePrefix: "myprefix",
},
});
// ./app/server/src/libs/auth.ts
export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg",
schema: schema,
}),
appName: "MySuperApp",
trustedOrigins: [env.CORS_ORIGIN], // http://localhost:8000
emailAndPassword: {
enabled: true,
autoSignInAfterVerification: false,
},

/* Plugins configuration */
plugins: [
openAPI(),
organization(),
phoneNumber({
// ...
emailOTP({
// ...
}),
],

/* Better-auth schema change */
user: {
additionalFields: {
first_name: {
type: "string",
required: true,
},
onboarding: {
type: "string",
required: true,
},
},
},

/* Advenced configuration */
advanced: {
cookiePrefix: "myprefix",
},
});
Firefox CORS errors
1 Reply
Kinan
KinanOP2w ago
Auth client config
// ./app/wrb/src/lib/auth-client.ts

import { auth } from "@/libs/auth";
// ...

export const authClient = createAuthClient({
baseURL: "http://localhost:8100",
fetchOptions: {
credentials: "include",
},
plugins: [
inferAdditionalFields({
user: {
first_name: {
type: "string",
required: false,
},
onboarding: {
type: "string",
required: false,
},
},
}),

phoneNumberClient(),
organizationClient(),
emailOTPClient(),
],
});
// ./app/wrb/src/lib/auth-client.ts

import { auth } from "@/libs/auth";
// ...

export const authClient = createAuthClient({
baseURL: "http://localhost:8100",
fetchOptions: {
credentials: "include",
},
plugins: [
inferAdditionalFields({
user: {
first_name: {
type: "string",
required: false,
},
onboarding: {
type: "string",
required: false,
},
},
}),

phoneNumberClient(),
organizationClient(),
emailOTPClient(),
],
});
Elysia server config
// ./apps/server/src/index.ts
aot: true,
detail: {
servers: [
{
url: `http://localhost:8100`,
},
],
},
})
// CORS configuration
.use(
cors({
origin: [env.CORS_ORIGIN], // http://localhost:8000
credentials: true,
})
)

// Authentication middleware
.mount(auth.handler)


// Swagger documentation
.use(
swagger({
documentation: {
servers: [
{
url: `http://localhost:8100`,
description: "Local server",
},
],
},
})
)
.use(serverConfig)
.use(onboardingRoutes)
.get("/", () => "OK")
.listen(8100);
// ./apps/server/src/index.ts
aot: true,
detail: {
servers: [
{
url: `http://localhost:8100`,
},
],
},
})
// CORS configuration
.use(
cors({
origin: [env.CORS_ORIGIN], // http://localhost:8000
credentials: true,
})
)

// Authentication middleware
.mount(auth.handler)


// Swagger documentation
.use(
swagger({
documentation: {
servers: [
{
url: `http://localhost:8100`,
description: "Local server",
},
],
},
})
)
.use(serverConfig)
.use(onboardingRoutes)
.get("/", () => "OK")
.listen(8100);
Minimal example :
import { useForm } from "react-hook-form";
import { useState } from "react";
import { toast } from "sonner";
import { authClient } from "@/lib/auth-client";

type FormValues = {
email: string;
password: string;
};

export function MinimalSignupForm() {
const { register, handleSubmit, setError } = useForm<FormValues>();
const [emailChecked, setEmailChecked] = useState(false);

const onSubmit = async (data: FormValues) => {
try {
if (!emailChecked) {
const res = await fetch(`/api/check-email?email=${data.email}`);
const result = await res.json();

if (result.status === "not_available") {
setError("email", { type: "manual", message: "Email déjà utilisé" });
return;
}

setEmailChecked(true);
return;
}
import { useForm } from "react-hook-form";
import { useState } from "react";
import { toast } from "sonner";
import { authClient } from "@/lib/auth-client";

type FormValues = {
email: string;
password: string;
};

export function MinimalSignupForm() {
const { register, handleSubmit, setError } = useForm<FormValues>();
const [emailChecked, setEmailChecked] = useState(false);

const onSubmit = async (data: FormValues) => {
try {
if (!emailChecked) {
const res = await fetch(`/api/check-email?email=${data.email}`);
const result = await res.json();

if (result.status === "not_available") {
setError("email", { type: "manual", message: "Email déjà utilisé" });
return;
}

setEmailChecked(true);
return;
}
await authClient.signUp.email(
{
email: data.email,
password: data.password,
name: "",
first_name: "",
onboarding: "step2",
},
{
onSuccess: () => toast.success("Compte créé avec succès !"),
onError: () => toast.error("Erreur lors de la création du compte"),
}
);

/* Fetch alternative

const res = await fetch("http://localhost:8100/api/auth/sign-up/email", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: data.email,
password: data.password,
name: "",
first_name: "",
onboarding: "step2",
}),
});

if (!res.ok) throw new Error("Erreur réseau");
toast.success("Compte créé avec succès !");
*/
} catch (error) {
toast.error("Une erreur est survenue");
}
};

return (
<form onSubmit={handleSubmit(onSubmit)}>
<input placeholder="Email" {...register("email")} />
<input placeholder="Mot de passe" type="password" {...register("password")} />
<button type="submit">Créer un compte</button>
</form>
);
}
await authClient.signUp.email(
{
email: data.email,
password: data.password,
name: "",
first_name: "",
onboarding: "step2",
},
{
onSuccess: () => toast.success("Compte créé avec succès !"),
onError: () => toast.error("Erreur lors de la création du compte"),
}
);

/* Fetch alternative

const res = await fetch("http://localhost:8100/api/auth/sign-up/email", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: data.email,
password: data.password,
name: "",
first_name: "",
onboarding: "step2",
}),
});

if (!res.ok) throw new Error("Erreur réseau");
toast.success("Compte créé avec succès !");
*/
} catch (error) {
toast.error("Une erreur est survenue");
}
};

return (
<form onSubmit={handleSubmit(onSubmit)}>
<input placeholder="Email" {...register("email")} />
<input placeholder="Mot de passe" type="password" {...register("password")} />
<button type="submit">Créer un compte</button>
</form>
);
}
Thank you in advance for your help, and thank you for creating such a great library as Better-Auth.

Did you find this page helpful?