Help in resolving CORS issue with Better Auth

This is my first time using Better Auth and I am pairing it with Elysia and a Solid SPA. The Elysia backend is a dedicated backend-for-frontend that will serve the frontend in production so they will share the same origin url. I am currently running into CORS issues when I attempt to sign in using the username plug-in. Below are my configurations: For my frontend SPA, here is my vite.config.ts. The thing to note about it is the server.proxy configuration I have defined. When my frontend makes a request to http://localhost:3000/api/* it'll route it to port 8000 instead as that is the port where my ElysiaJS backend runs on in a sidecar shell.
import { defineConfig as defineViteConfig, mergeConfig } from "vite";
import solidPlugin from "vite-plugin-solid";

const viteConfig = defineViteConfig({
plugins: [solidPlugin()],
server: {
port: 3000,
proxy: {
// Proxy API requests to the backend port in development
"/api": "http://localhost:8000",
},
},
build: {
target: "esnext",
},
resolve: {
conditions: ["development", "browser"],
},
});

// ...other stuff
import { defineConfig as defineViteConfig, mergeConfig } from "vite";
import solidPlugin from "vite-plugin-solid";

const viteConfig = defineViteConfig({
plugins: [solidPlugin()],
server: {
port: 3000,
proxy: {
// Proxy API requests to the backend port in development
"/api": "http://localhost:8000",
},
},
build: {
target: "esnext",
},
resolve: {
conditions: ["development", "browser"],
},
});

// ...other stuff
My frontend Better Auth client config is the following:
import { usernameClient } from "better-auth/client/plugins";
import { createAuthClient } from "better-auth/solid";

export const authClient = createAuthClient({
baseURL: "http://localhost:3000",
plugins: [usernameClient()],
});
import { usernameClient } from "better-auth/client/plugins";
import { createAuthClient } from "better-auth/solid";

export const authClient = createAuthClient({
baseURL: "http://localhost:3000",
plugins: [usernameClient()],
});
Moving on to the backend side of things, here is my Better Auth server config:
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { username } from "better-auth/plugins";

import { db } from "../drizzle/db";

export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg",
}),
plugins: [username()],
session: {
cookieCache: {
enabled: true,
maxAge: 5 * 60 // Cache duration in seconds
}
},
});
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { username } from "better-auth/plugins";

import { db } from "../drizzle/db";

export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg",
}),
plugins: [username()],
session: {
cookieCache: {
enabled: true,
maxAge: 5 * 60 // Cache duration in seconds
}
},
});
And here is my Elysia setup for Better Auth:
import type { Session, User } from "better-auth";
import { type Context, Elysia } from "elysia";

import { auth } from "../lib/auth";

// user middleware (compute user and session and pass to routes)
const userMiddleware = async (request: Request) => {
const session = (await auth.api.getSession({ headers: request.headers })) || {
user: null,
session: null,
};

return {
user: session.user,
session: session.session,
};
};

// https://www.better-auth.com/docs/integrations/elysia
const betterAuthView = async (context: Context) => {
const BETTER_AUTH_ACCEPT_METHODS = ["POST", "GET"];

// validate request method
if (BETTER_AUTH_ACCEPT_METHODS.includes(context.request.method)) {
return auth.handler(context.request);
} else {
context.error(405);
}
};

// user info view
// type User can be export from `typeof auth.$Infer.Session.user`
// type Session can be export from `typeof auth.$Infer.Session.session`
const userInfo = (user: User | null, session: Session | null) => {
return {
user: user,
session: session,
};
};

const api = new Elysia({ prefix: "/api" })
.derive(({ request }) => userMiddleware(request))
.all("/auth/*", betterAuthView)
.get("/user", ({ user, session }) => userInfo(user, session))
.get("/hello", () => ({ message: "Hello World API!" }));

export default api;
import type { Session, User } from "better-auth";
import { type Context, Elysia } from "elysia";

import { auth } from "../lib/auth";

// user middleware (compute user and session and pass to routes)
const userMiddleware = async (request: Request) => {
const session = (await auth.api.getSession({ headers: request.headers })) || {
user: null,
session: null,
};

return {
user: session.user,
session: session.session,
};
};

// https://www.better-auth.com/docs/integrations/elysia
const betterAuthView = async (context: Context) => {
const BETTER_AUTH_ACCEPT_METHODS = ["POST", "GET"];

// validate request method
if (BETTER_AUTH_ACCEPT_METHODS.includes(context.request.method)) {
return auth.handler(context.request);
} else {
context.error(405);
}
};

// user info view
// type User can be export from `typeof auth.$Infer.Session.user`
// type Session can be export from `typeof auth.$Infer.Session.session`
const userInfo = (user: User | null, session: Session | null) => {
return {
user: user,
session: session,
};
};

const api = new Elysia({ prefix: "/api" })
.derive(({ request }) => userMiddleware(request))
.all("/auth/*", betterAuthView)
.get("/user", ({ user, session }) => userInfo(user, session))
.get("/hello", () => ({ message: "Hello World API!" }));

export default api;
On the frontend, when I attempt to execute authClient.signIn.username(...) I get the following error:
ERROR [Better Auth]: Invalid origin: http://localhost:3000
INFO [Better Auth]: If it's a valid URL, please add http://localhost:3000 to trustedOrigins in your auth config
Current list of trustedOrigins: http://localhost:3000/api/auth,http://localhost:8000
ERROR [Better Auth]: Invalid origin: http://localhost:3000
INFO [Better Auth]: If it's a valid URL, please add http://localhost:3000 to trustedOrigins in your auth config
Current list of trustedOrigins: http://localhost:3000/api/auth,http://localhost:8000
Clearly, http://localhost:3000 origin is not on that list which is why I'm getting hit with CORS, but I guess I'm wondering the question why since http://localhost:3000/api/auth is there. And what is the recommended way to resolve this? Hoping to avoid explicit origins..
0 Replies
No replies yetBe the first to reply to this messageJoin

Did you find this page helpful?