6 months ago
I recently upgraded my project from the Free plan to the Hobby plan. Since the upgrade, my Express.js backend hosted on Railway is experiencing CORS preflight failures. Preflight OPTIONS requests to endpoints such as /api/auth/login are failing with the following error in the browser:
Access to XMLHttpRequest at 'https://consultancypro-production.up.railway.app/api/auth/login' from origin 'https://consultancy-frontend-pro.vercel.app' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Project Details:
Backend Stack: Node.js + Express.js + Sequelize + MySQL
CORS Setup: Using
corsmiddleware in Express withcredentials: trueand a whitelist of allowed origins. Middleware is placed before routes and handles preflightOPTIONSrequests.Status: This setup was working correctly on the Free plan. After upgrading to the Hobby plan, all cross-origin POST requests fail with the error above.
I have confirmed that:
My frontend origin matches the whitelist.
The backend is reachable and responding to direct requests.
Preflight
OPTIONSrequests are reaching the server but are missing theAccess-Control-Allow-Originheader.
Could you please advise if there are any changes in reverse proxy, preflight handling, or other plan-related differences on the Hobby plan that could be causing this issue? Guidance on resolving this would be highly appreciated.
6 Replies
6 months ago
This thread has been marked as public for community involvement, as it does not contain any sensitive or personal information. Any further activity in this thread will be visible to everyone.
Status changed to Open brody • 6 months ago
6 months ago
Hey! Can you try adding something like this to your server.js before your other routes and share the output?
- You can adjust the configuration (add, remove, or change values) based on your needs.
You can find the docs with all options here => https://expressjs.com/en/resources/middleware/cors.html?utm_source=chatgpt.com#configuration-options
const corsOptions = {
origin: 'https://consultancy-frontend-pro.vercel.app',
credentials: true,
methods: ['GET','HEAD','PUT','PATCH','POST','DELETE','OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
maxAge: 86400
};
app.use(cors(corsOptions));
app.options('*', cors(corsOptions));
6 months ago
okay let me give it a try
6 months ago
Did it work?
6 months ago
no it didn't , but it will work if i do a entirely new deployment.
6 months ago
okay any public review
, it only has to do with the preflight.
6 months ago
Short answer
There’s no plan-level proxy change on Hobby that alters CORS. If a fresh deployment works but the current one fails, it’s almost always (a) middleware order or (b) stale deploy not picking up config.
---
.
Do this (in order):
1. Handle OPTIONS before everything else (incl. auth).
js
import cors from 'cors';
const ORIGINS = ['https://consultancy-frontend-pro.vercel.app']; // add others if needed
const corsOptions = {
origin: ORIGINS,
credentials: true,
methods: ['GET','HEAD','PUT','PATCH','POST','DELETE','OPTIONS'],
// Tip: omit allowedHeaders to let the library reflect Access-Control-Request-Headers
maxAge: 86400,
};
app.use((req,res,next)=>{ res.set('Vary','Origin'); next(); });
app.options('*', cors(corsOptions)); // preflight first
app.use(cors(corsOptions)); // then regular routes
// ⬇ put auth/routers AFTER cors(Express cors docs show origin, credentials, etc. and using app.options('*', cors(...)) for preflight.)
---
2. Remove allowedHeaders unless you must lock it down.
Hard-coding headers can fail preflight if the browser asks for extra ones (the middleware will reflect them automatically when not specified).
---
3. Verify with cURL (should return 204 + CORS headers):
bash
curl -i -X OPTIONS 'https://consultancypro-production.up.railway.app/api/auth/login' \
-H 'Origin: https://consultancy-frontend-pro.vercel.app' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: Content-Type, Authorization'If you don’t see Access-Control-Allow-Origin echoed to your origin and Access-Control-Allow-Credentials: true, your CORS middleware still isn’t running. See MDN note on the missing header error.
---
4. Redeploy to apply changes.
Env/setting changes in Railway are staged until you click Deploy; only then does the running service pick them up. (A “new deployment” working aligns with this.)
---
.
Notes
Hobby vs Free: pricing/limits differ, but CORS behavior is app-side; there’s no plan toggle that adds/removes CORS headers.
If you use
credentials: true, don’t useorigin: '*'; either list exact origins or set a function/`true` to reflect the request origin.If an auth middleware rejects
OPTIONS, exempt it:if (req.method === 'OPTIONS') return next();.
That sequence fixes nearly all “preflight started failing after an upgrade” reports; your successful fresh deploy is the tell that ordering/staging was the culprit.