CloudFlare and Server Side Whitelisting for CORS
Overview
The CORs headers need to be set explicitly on the server. For some websites, CloudFlare can be used to control CORS header logic at the edge.
Note that you will also need to ensure that Origin Server denies all IPs except the CloudFlare IP (this will need to be AT the server level, not cloudlfare). This will capture all the use cases where clients are DIRECTLY accessing the I.P. address of the website (instead of the URL, which CloudFlare will address)
How a Server Explicitly Sets CORS Headers for an HTTP Request
A server explicitly sets CORS headers by including them in the HTTP response to a cross-origin request. These headers instruct the browser whether or not to allow frontend JavaScript from another origin to access the response data.
Example: CORS Headers in an HTTP Response
Access-Control-Allow-Origin: https://example-client.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true
How to Set CORS Headers in Different Environments
1. Node.js / Express
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "https://example-client.com");
res.header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
res.header("Access-Control-Allow-Credentials", "true");
next();
});
Or use the built-in middleware:
const cors = require('cors');
const corsOptions = {
origin: "https://example-client.com",
methods: "GET,POST,PUT,DELETE",
credentials: true
};
app.use(cors(corsOptions));
2. Python / Flask
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app, resources={r"/api/*": {"origins": "https://example-client.com"}}, supports_credentials=True)
3. Apache HTTP Server
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "https://example-client.com"
Header set Access-Control-Allow-Methods "GET,POST,PUT,DELETE"
Header set Access-Control-Allow-Headers "Content-Type, Authorization"
Header set Access-Control-Allow-Credentials "true"
</IfModule>
4. Nginx
location /api/ {
add_header 'Access-Control-Allow-Origin' 'https://example-client.com' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type';
add_header 'Access-Control-Allow-Credentials' 'true';
}
Preflight Requests (OPTIONS)
For requests that include custom headers or use non-simple HTTP methods (like PUT, DELETE), browsers send a preflight request using OPTIONS.
To support that, servers should handle OPTIONS requests and return appropriate CORS headers.
Example in Node.js:
app.options("*", (req, res) => {
res.header("Access-Control-Allow-Origin", "https://example-client.com");
res.header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
res.sendStatus(204);
});
Security Note
Avoid using:
Access-Control-Allow-Origin: *
if you’re sending cookies or Authorization headers. In such cases, use a specific origin and also set:
Access-Control-Allow-Credentials: true
Using Cloudflare to Maintain a Dynamic Origin Whitelist
If your API is hosted behind Cloudflare, you can use Cloudflare Workers or Cloudflare Gateway Rules to dynamically control and enforce CORS logic at the edge — before the request even reaches your origin server.
Example Using a Cloudflare Worker
addEventListener("fetch", event => {
event.respondWith(handleRequest(event.request));
});
const allowedOrigins = [
"https://example-client.com",
"https://admin.example.com"
];
async function handleRequest(request) {
const origin = request.headers.get("Origin");
const response = await fetch(request);
const newHeaders = new Headers(response.headers);
if (allowedOrigins.includes(origin)) {
newHeaders.set("Access-Control-Allow-Origin", origin);
newHeaders.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
newHeaders.set("Access-Control-Allow-Headers", "Authorization, Content-Type");
newHeaders.set("Access-Control-Allow-Credentials", "true");
}
return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: newHeaders
});
}
This gives you full control over origin validation and CORS behavior at the network edge, improving performance and offloading logic from your app servers.
You can even maintain the whitelist in a KV store or external API and update it dynamically without redeploying infrastructure.
Leave a Reply