DEV Community

Athreya aka Maneshwar
Athreya aka Maneshwar

Posted on

CORS in Parse Server: Making Cross-Origin Work Without the Headache

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 Origin header)
  • 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();
Enter fullscreen mode Exit fullscreen mode

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",
    ],
  })
);
Enter fullscreen mode Exit fullscreen mode

A few things to highlight:

  • origin === undefined is allowed — useful for scripts or apps without a browser.
  • We specifically whitelist localhost origins.
  • 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);
Enter fullscreen mode Exit fullscreen mode

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: true in 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": "...",
  },
});
Enter fullscreen mode Exit fullscreen mode

The Gotchas

  • Don't wildcard origin: "*", especially with credentials: 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
Enter fullscreen mode Exit fullscreen mode

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.

LiveAPI Demo

If you're tired of updating Swagger manually or syncing Postman collections, give it a shot.

Top comments (0)