@@ -58,9 +58,20 @@ export function createApp() {
5858 const isTest = env . NODE_ENV === "test" ;
5959 const isProd = env . NODE_ENV === "production" ;
6060
61- // This must match the browser's Origin exactly (no trailing slash).
62- // Example: "https://thehumanpatternlab.com"
63- const uiOrigin = env . UI_BASE_URL ?? "http://localhost:5173" ;
61+ // CORS origins come from UI_BASE_URL (comma-separated allowed).
62+ // Browser Origin header must match EXACTLY (no trailing slash).
63+ // Example: UI_BASE_URL="https://thehumanpatternlab.com,https://ironkitsune.tech"
64+ const allowedOrigins =
65+ env . UI_ALLOWED_ORIGINS . length > 0
66+ ? env . UI_ALLOWED_ORIGINS
67+ : [ "http://localhost:5173" ] ;
68+ const corsOrigin = ( origin : string | undefined , callback : ( err : Error | null , allow ?: boolean ) => void ) => {
69+ if ( ! origin || allowedOrigins . includes ( origin ) ) {
70+ callback ( null , true ) ;
71+ } else {
72+ callback ( new Error ( `CORS: origin ${ origin } not allowed` ) ) ;
73+ }
74+ } ;
6475
6576 /* ===========================================================
6677 5) CORS (BEFORE SESSION IF CROSS-ORIGIN)
@@ -78,13 +89,13 @@ export function createApp() {
7889 =========================================================== */
7990 app . use (
8091 cors ( {
81- origin : uiOrigin ,
92+ origin : corsOrigin ,
8293 credentials : true ,
8394 } )
8495 ) ;
8596
8697// ✅ Force-handle ALL preflight requests
87- app . options ( / .* / , cors ( { origin : uiOrigin , credentials : true } ) ) ;
98+ app . options ( / .* / , cors ( { origin : corsOrigin , credentials : true } ) ) ;
8899 app . use ( ( req , _res , next ) => {
89100 if ( req . method === "OPTIONS" ) {
90101 console . log ( "🧪 Preflight:" , req . headers . origin , req . headers [ "access-control-request-method" ] , req . url ) ;
@@ -240,3 +251,4 @@ export function createApp() {
240251 registerOpenApiRoutes ( app ) ;
241252 return app ;
242253}
254+
0 commit comments