From 35c6371d4827b6bde92011707d5706c462176daa Mon Sep 17 00:00:00 2001 From: Kenneth Date: Mon, 23 Mar 2026 00:31:23 +0000 Subject: [PATCH] fix(backend): add CORS and disable CSRF in dev (#92) * fix(backend): add CORS middleware and disable CSRF in dev - Add CORS middleware for /api/auth/* and global routes - Disable better-auth CSRF origin check when NODE_ENV != production Co-authored-by: Ona * fix: gate permissive CORS to dev only In production, only origins listed in CORS_ORIGINS env var are allowed. In dev, any origin is reflected back. Co-authored-by: Ona --------- Co-authored-by: Ona --- apps/aelis-backend/src/auth/index.ts | 3 +++ apps/aelis-backend/src/server.ts | 29 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/apps/aelis-backend/src/auth/index.ts b/apps/aelis-backend/src/auth/index.ts index 351a25e..0a9b567 100644 --- a/apps/aelis-backend/src/auth/index.ts +++ b/apps/aelis-backend/src/auth/index.ts @@ -16,6 +16,9 @@ export function createAuth(db: Database) { provider: "pg", schema, }), + advanced: { + disableCSRFCheck: process.env.NODE_ENV !== "production", + }, emailAndPassword: { enabled: true, }, diff --git a/apps/aelis-backend/src/server.ts b/apps/aelis-backend/src/server.ts index 22fa66b..300cb96 100644 --- a/apps/aelis-backend/src/server.ts +++ b/apps/aelis-backend/src/server.ts @@ -1,4 +1,5 @@ import { Hono } from "hono" +import { cors } from "hono/cors" import { registerAdminHttpHandlers } from "./admin/http.ts" import { createRequireAdmin } from "./auth/admin-middleware.ts" @@ -50,6 +51,34 @@ function main() { const app = new Hono() + const isDev = process.env.NODE_ENV !== "production" + const allowedOrigins = process.env.CORS_ORIGINS?.split(",").map((o) => o.trim()) ?? [] + + function resolveOrigin(origin: string): string | undefined { + if (isDev) return origin + return allowedOrigins.includes(origin) ? origin : undefined + } + + app.use( + "/api/auth/*", + cors({ + origin: resolveOrigin, + allowHeaders: ["Content-Type", "Authorization"], + allowMethods: ["POST", "GET", "OPTIONS"], + exposeHeaders: ["Content-Length"], + maxAge: 600, + credentials: true, + }), + ) + + app.use( + "*", + cors({ + origin: resolveOrigin, + credentials: true, + }), + ) + app.get("/health", (c) => c.json({ status: "ok" })) const authSessionMiddleware = createRequireSession(auth)