Hi there! I'm Maneshwar. Right now, I’m building LiveAPI, a first-of-its-kind tool that helps you automatically index API endpoints across all your repositories. LiveAPI makes it easier to discover, understand, and interact with APIs in large infrastructures.
So you're running a Parse Server, building APIs, and your frontend is yelling:
Access to fetch at 'http://your-api' from origin 'http://localhost:3000' has been blocked by CORS policy...
We've all been there. In this post, let's break down how to properly set up CORS in Parse Server, especially when you're self-hosting it with Express. We'll walk through real-world needs like:
- Allowing dev environments like
localhost - Restricting production to specific domains
- Handling mobile apps and curl requests (with no
Originheader) - Debugging what’s going on
The Setup
You're probably starting with a basic Express + Parse Server app like this:
const Express = require("express");
const ParseServer = require("parse-server").ParseServer;
const cors = require("cors");
const app = Express();
Why CORS Matters
CORS (Cross-Origin Resource Sharing) decides which frontends can talk to your backend, especially when they're on different origins (protocol + domain + port). Without proper CORS setup, your frontend will be blocked from making requests — even if your API is working fine.
Our CORS Strategy
Here’s what we want to achieve:
| Use Case | Should Work? |
|---|---|
http://localhost:3000 during dev |
✅ |
https://internal.dev.to production dashboard |
✅ |
curl or mobile app (no Origin) |
✅ |
| Random site trying to use our API | ❌ |
CORS Middleware in Action
This is the core of our CORS setup:
app.use(
cors({
origin: function (origin, callback) {
if (!origin) return callback(null, true); // mobile apps / curl
if (origin.startsWith("http://localhost:") || origin.startsWith("https://localhost:")) {
return callback(null, true); // dev machines
}
const allowedOrigins = ["https://dev.to", "https://internal.dev.to"];
if (allowedOrigins.includes(origin)) {
return callback(null, true);
}
callback(new Error("Not allowed by CORS"));
},
credentials: true,
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
allowedHeaders: [
"Content-Type",
"Authorization",
"X-Parse-Application-Id",
"X-Parse-REST-API-Key",
"X-Parse-Master-Key",
"X-Parse-Session-Token",
],
})
);
A few things to highlight:
-
origin === undefinedis allowed — useful for scripts or apps without a browser. - We specifically whitelist
localhostorigins. - We explicitly allow your real production domains (
dev.to, etc). - Anything else? Rejected.
Bonus: Debug the Origins
Drop this in before your routes to log what’s actually hitting your server:
function logOriginAndHost(req, res, next) {
console.log("origin:", req.get("origin"));
console.log("host:", req.get("host"));
next();
}
app.use(logOriginAndHost);
This helps when you're wondering:
"Why the hell is this being blocked?"
Don’t Forget credentials: true
If your frontend needs to send cookies or headers like Authorization or X-Parse-Session-Token, don’t forget:
-
credentials: truein CORS config (backend) -
credentials: "include"in fetch/axios (frontend)
Example:
fetch("https://yourapi.dev/parse/classes/SomeObject", {
method: "GET",
credentials: "include",
headers: {
"X-Parse-Application-Id": "...",
"X-Parse-Session-Token": "...",
},
});
The Gotchas
- Don't wildcard
origin: "*", especially withcredentials: true— it won’t work. - Don’t trust just
req.headers.origin— always validate it. - Always set the right headers for Parse (
X-Parse-*).
Final Thoughts
CORS isn’t magic. It’s just a server-side filter. With proper control, your Parse Server can safely talk to:
- Frontends during development
- Trusted production apps
- Mobile clients and scripts
Just be explicit about what you allow and you’re good to go.
Repo Tip
If you're working in a team, drop a comment like this in your config:
// CORS rules: only allow trusted origins
// Update this list when adding frontend apps
Because otherwise, your teammate will change a subdomain and wonder why everything breaks.
LiveAPI helps you get all your backend APIs documented in a few minutes.
With LiveAPI, you can generate interactive API docs that allow users to search and execute endpoints directly from the browser.
If you're tired of updating Swagger manually or syncing Postman collections, give it a shot.

Top comments (0)