Downloads

Download ColdFusion CORS Policy Examples

This article provides a complete, production-ready set of ColdFusion CORS (Cross-Origin Resource Sharing) policy examples that you can Download or copy into your projects. The resource focuses on secure, configurable headers for preflight handling, credentialed requests, and reverse-proxy deployments, helping you solve “blocked by CORS policy” errors quickly and safely.


Overview

CORS governs whether a browser is allowed to call your ColdFusion endpoints from a different origin (domain, subdomain, or port). When not configured correctly, AJAX/Fetch calls to your CFML REST APIs, JSON endpoints, or static files can fail with opaque errors.

This resource gives you:

  • A tested, extensible Application.cfc implementation for Adobe ColdFusion and Lucee.
  • Web server and container-level examples (Tomcat, IIS, Nginx, Apache) when you prefer to emit headers before requests reach ColdFusion.
  • Ready-to-run tests with curl and browser Fetch, plus Best practices that reduce risk while improving developer productivity.

Use these examples to implement Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Allow-Credentials, Access-Control-Max-Age, Vary, and reliable handling of OPTIONS preflight requests.


What You’ll Get

– CFML application-level CORS helper (Application.cfc, CORS.cfc, and a lightweight include).
– Server and proxy samples (Tomcat web.xml filter, IIS CORS module config, Nginx and Apache header rules).
– Test assets (curl command set and a minimal browser Fetch page).
– Documentation notes and Best practices.

File contents overview:

  • cfml/Application.cfc — Request lifecycle hooks and CORS functions
  • cfml/CORS.cfc — reusable component with origin checks and header setters
  • cfml/cors-include.cfm — drop-in include for legacy apps without Application.cfc edits
  • server/tomcat/web.xml — Apache Tomcat CorsFilter snippet
  • server/iis/web.config — IIS CORS Module example
  • server/nginx.conf — proxy/header rules with origin whitelisting
  • server/httpd.conf — Apache mod_headers + SetEnvIf example
  • test/index.html — small page to test fetch() cross-origin calls
  • test/curl-commands.txt — copy-paste curl tests for preflight and simple requests
  • docs/README.txt — Quick reference and notes

Supported Environments

– Adobe ColdFusion 2018, 2021, 2023
Lucee 5.3+ and Lucee 6+
– Tomcat 8.5, 9, 10
– IIS 10+ with the IIS CORS Module
– Nginx 1.18+
– Apache HTTP Server 2.4+


Quick Start

Option A — App-level CORS in CFML (Application.cfc)

Paste the following Application.cfc into the root of your app or merge the relevant parts into your existing file. It safely reflects allowed origins, handles OPTIONS preflight, and sets headers for actual requests. Works for APIs and traditional pages.

See also  Download IIS Rewrite Rules Template for ColdFusion Apps

Note: This uses script Syntax for cfheader and runs on Adobe CF and Lucee.

cfml
component {

this.name = “CORSExampleApp”;
this.sessionManagement = false;

// Toggle credential support (cookies, Authorization headers, etc.)
variables.allowCredentials = true;

// Allowed origins. Supports exact matches and simple wildcard subdomains.
variables.allowedOriginPatterns = [
https://example.com“,
https://*.example.org“,
http://localhost:3000“,
http://127.0.0.1:8080
];

// Allow/Expose/MaxAge choices
variables.allowedMethods = “GET,POST,PUT,PATCH,DELETE,OPTIONS”;
variables.allowedHeaders = “Authorization,Content-Type,X-Requested-With”;
variables.exposedHeaders = “X-Request-Id”;
variables.maxAgeSeconds = 3600;

function onRequestStart(targetPage){
var req = getHttpRequestData();
var method = uCase( cgi.request_method ?: “” );
var origin = req.headers[“Origin”] ?: “”;

if ( method eq "OPTIONS" && isCORSPreflight(req) ) {
  // Preflight: respond without running the target page
  addCORSHeaders(origin, req);
  // 204 No Content is typical for preflight success
  cfheader(statuscode=204, statustext="No Content");
  // Required by Lucee/ACF to stop processing further
  abort;
}
// For non-OPTIONS requests, add CORS headers (if allowed)
addCORSHeaders(origin, req);
return true;

}

function onRequest(targetPage) {
include arguments.targetPage;
}

function onError(exception, eventName){
// Ensure CORS headers still emitted on error responses
var req = getHttpRequestData();
addCORSHeaders(req.headers[“Origin”] ?: “”, req);
}

private boolean function isCORSPreflight(req){
return structKeyExists(req.headers, “Access-Control-Request-Method”);
}

private boolean function isAllowedOrigin(origin){
if (!len(origin)) return false;

// Simple matcher for exact and wildcard subdomain patterns.
for (var pattern in variables.allowedOriginPatterns) {
  if (findNoCase("*.", pattern)) {
    var base = rereplace(pattern, "^\s*https?://\*\.", "", "all");
    var re = "^https?://([A-Za-z0-9-]+\.)*#REReplace(escapeRE(base),'\.','\.', 'all')#(?::\d+)?$";
    if (reFindNoCase(re, origin)) return true;
  } else {
    if (compareNoCase(pattern, origin) == 0) return true;
  }
}
return false;

}

private void function addCORSHeaders(origin, req){
// Always vary on Origin for caches/proxies
cfheader(name=”Vary”, value=”Origin”);

if (!isAllowedOrigin(origin)) {
  // Optionally lock down non-matching origins by not setting CORS headers
  return;
}

// With credentials, you must echo the specific origin (no "*")
cfheader(name="Access-Control-Allow-Origin", value=origin);

if (variables.allowCredentials) {
  cfheader(name="Access-Control-Allow-Credentials", value="true");
}

// Preflight extras
if (structKeyExists(req.headers, "Access-Control-Request-Method")) {
  cfheader(name="Access-Control-Allow-Methods", value=variables.allowedMethods);

  // Reflect requested headers or apply a controlled allow-list
  var requested = req.headers["Access-Control-Request-Headers"] ?: "";
  if (len(requested)) {
    // Normalize commas/spaces and lower-case for consistency
    cfheader(name="Access-Control-Allow-Headers", value= lcase(reReplace(requested, "\s+", "", "all")) );
  } else {
    cfheader(name="Access-Control-Allow-Headers", value=variables.allowedHeaders);
  }

  cfheader(name="Access-Control-Max-Age", value= variables.maxAgeSeconds );
  // Help caches vary per requested headers too
  if (len(requested)) cfheader(name="Vary", value="Access-Control-Request-Headers");
} else {
  // Actual requests can expose additional headers
  if (len(variables.exposedHeaders)) {
    cfheader(name="Access-Control-Expose-Headers", value=variables.exposedHeaders);
  }
}

}

// Utility for regex escaping of host fragments
private string function escapeRE(str){
return rereplace(str, “([.\+*\?[\^]\$(){}\=!\<>|\:-])”, “\\1”, “all”);
}
}

If you cannot modify Application.cfc, include the header logic at the top of each API template using the provided cors-include.cfm.

Option B — Web server / container CORS headers (before ColdFusion)

Useful when serving mixed assets via a Reverse proxy, or when you prefer centralized governance.

  • Tomcat web.xml (CorsFilter)
    xml


    CorsFilter
    org.apache.catalina.filters.CorsFilter
    cors.allowed.origins https://example.com,http://localhost:3000
    cors.allowed.methods GET,POST,PUT,PATCH,DELETE,OPTIONS
    cors.allowed.headers Authorization,Content-Type,X-Requested-With
    cors.exposed.headers X-Request-Id
    cors.support.credentials true
    cors.preflight.maxage 3600


    CorsFilter
    /*

  • IIS (IIS CORS Module)
    xml





    GET,POST,PUT,PATCH,DELETE,OPTIONS

    X-Request-Id
    3600



    GET,POST,PUT,PATCH,DELETE,OPTIONS



  • Nginx (Reverse proxy)
    nginx
    map $http_origin $cors_allow {
    default “”;
    ~^https?://(.*.example.org|example.com|localhost(:\d+)?|127.0.0.1(:\d+)?)$ $http_origin;
    }

server {

See also  Download the ColdFusion Upgrade Pre-Flight Checklist (PDF)

if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin $cors_allow always;
add_header Access-Control-Allow-Credentials true always;
add_header Access-Control-Allow-Methods “GET,POST,PUT,PATCH,DELETE,OPTIONS” always;
add_header Access-Control-Allow-Headers $http_access_control_request_headers always;
add_header Access-Control-Max-Age 3600 always;
add_header Vary “Origin, Access-Control-Request-Headers” always;
return 204;
}

add_header Access-Control-Allow-Origin $cors_allow always;
add_header Access-Control-Allow-Credentials true always;
add_header Access-Control-Expose-Headers “X-Request-Id” always;

location / {
proxy_pass http://cfml_upstream;
}
}

  • Apache HTTPD (mod_headers + SetEnvIf)
    apache
    SetEnvIf Origin “^https?://(.*.example.org|example.com|localhost(:[0-9]+)?|127.0.0.1(:[0-9]+)?)$” ORIGIN_OK=1

Header always set Access-Control-Allow-Origin “%{Origin}e” env=ORIGIN_OK
Header always set Access-Control-Allow-Credentials “true” env=ORIGIN_OK
Header always set Access-Control-Expose-Headers “X-Request-Id” env=ORIGIN_OK
Header always set Vary “Origin” env=ORIGIN_OK

RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=204,L]
Header always set Access-Control-Allow-Methods “GET,POST,PUT,PATCH,DELETE,OPTIONS” env=ORIGIN_OK
Header always set Access-Control-Allow-Headers “%{Access-Control-Request-Headers}e” env=ORIGIN_OK
Header always set Access-Control-Max-Age “3600” env=ORIGIN_OK


How to Configure

Step-by-Step

1) Decide where to implement CORS
– App-level (CFML): fine-grained control and dynamic per-route logic.
– Edge/server-level: one place to manage static assets and APIs together, often faster and simpler at scale.

  1. Install the files
  • App-level: Copy Application.cfc (or merge its functions) and CORS.cfc into your app root. Optionally use cors-include.cfm for legacy pages.
  • Server-level: Apply the appropriate snippet to Tomcat, IIS, Nginx, or Apache, then reload/restart.
  1. Configure allowed origins
  • Update allowedOriginPatterns (App-level) or lists in server configs. Prefer exact domains. Use wildcard subdomains only when necessary.
  • If you need credentials (cookies or Authorization headers), do not use “*”. Echo the requesting origin.
  1. Set methods, headers, and max age
  • Keep Access-Control-Allow-Headers to a minimal allow-list, or reflect the requested headers if you trust the client.
  • Access-Control-Max-Age reduces preflight noise (e.g., 3600 seconds).
  1. Test
  • Use the supplied curl commands and the test/index.html file to validate simple and preflight requests.
  • Verify browser DevTools > Network shows the expected CORS headers on both OPTIONS and the actual request.
  1. Deploy and monitor
  • In proxies or CDNs, ensure Vary: Origin is preserved to prevent cache poisoning.
  • Log or expose a X-Request-Id to correlate Server logs with client requests.

Best Practices

– Prefer a whitelist of exact origins; only use wildcard subdomains when you fully own the parent domain.
– Set Vary: Origin and, for preflight, add Vary: Access-Control-Request-Headers.
– If Access-Control-Allow-Credentials: true, never set Access-Control-Allow-Origin: *.
– Do not rely on CORS for Authentication or authorization; it’s a browser policy, not an app-level Security control.
– Limit Access-Control-Allow-Headers to necessary headers (e.g., Authorization, Content-Type).
– Cache preflight responses via Access-Control-Max-Age to reduce latency and server load.
– Ensure error responses and 4xx/5xx also include CORS headers, so the browser doesn’t mask useful information.
– For frameworks and route-specific rules, inject header logic at a central middleware or onRequestStart.


Benefits and Use Cases

– Faster Integration: Drop-in CFML code prevents trial-and-error on header Syntax.
– Works across stacks: Choose app-level or server-level depending on your Deployment and Architecture.
– Lower latency: Preflight caching via Access-Control-Max-Age reduces round trips.
Security-first defaults: Whitelists and Vary headers minimize cache and reflection risks.
– Common scenarios:
– Single-page apps calling ColdFusion REST endpoints from a different domain.
– Hybrid stacks where Nginx/Apache front a Tomcat-based ColdFusion engine.
– Mobile apps and Microservices using token-based auth (Authorization headers) with strict CORS.

See also  Download CommandBox Script Cookbook for ColdFusion

Troubleshooting and Testing

– Quick curl tests:
bash
# Preflight (OPTIONS)
curl -i -X OPTIONS https://api.yourdomain.com/v1/orders \
-H “Origin: http://localhost:3000” \
-H “Access-Control-Request-Method: POST” \
-H “Access-Control-Request-Headers: Authorization, Content-Type”

Actual request

curl -i -X POST https://api.yourdomain.com/v1/orders \
-H “Origin: http://localhost:3000” \
-H “Authorization: Bearer TEST” \
-H “Content-Type: application/json” \
-d ‘{“test”:true}’

  • Browser test page snippet (test/index.html):

<!doctype html>


  • Common pitfalls:
    • Missing CORS headers on error paths (ensure onError handlers add them).
    • Wildcard “*” used with credentials (blocked by browsers).
    • Reverse proxies stripping Vary or not forwarding Origin.
    • Preflight allowed headers/methods not aligned with actual calls.

Key Takeaways

– Implement CORS where it fits your Architecture: either in CFML with Application.cfc or at the web server/proxy layer.
– Use exact origin whitelists and echo the origin if you need credentials.
– Always emit Vary: Origin and consider Access-Control-Max-Age to improve Performance.
– Test both preflight (OPTIONS) and actual requests; verify headers in browser DevTools.


FAQ

Can I use Access-Control-Allow-Origin: * with cookies or Authorization headers?

No. If Access-Control-Allow-Credentials is true, browsers require a specific origin in Access-Control-Allow-Origin. Use an allow-list and echo the requesting origin when it matches.

Do all requests trigger a preflight?

No. “Simple” requests (GET/HEAD/POST with simple headers and certain content types) may skip preflight. Any custom headers (e.g., Authorization) or methods like PUT/DELETE typically trigger a preflight OPTIONS request.

How do I apply different CORS rules per route?

At the CFML layer, check CGI.SCRIPT_NAME or route information inside onRequestStart and branch your allowedOrigins/methods accordingly. At the proxy/server layer, use location blocks (Nginx), Directory/Location sections (Apache), or separate filter mappings (Tomcat) for fine-grained control.

Why do I need Vary: Origin?

Without Vary: Origin, caches and CDNs can serve a response generated for one origin to another, causing broken behavior or security leaks. Vary instructs caches to keep separate variants per origin.

What’s the difference between CORS and CSP?

CORS regulates cross-origin network requests and responses in the browser. CSP (Content Security Policy) governs which sources can load scripts, styles, images, etc. They complement each other but solve different problems.


Download and Next Steps

– Copy the code examples above into the indicated files and adapt the origin lists, methods, and headers to your environment.
– If you need a zip bundle of these examples, combine the snippets under a folder structure matching the “What You’ll Get” section.
– Tip: Externalize origin lists via environment variables (getSystemEnvironment()) to avoid hardcoding per environment (dev/stage/prod).

About the author

Aaron Longnion

Aaron Longnion

Hey there! I'm Aaron Longnion — an Internet technologist, web software engineer, and ColdFusion expert with more than 24 years of experience. Over the years, I've had the privilege of working with some of the most exciting and fast-growing companies out there, including lynda.com, HomeAway, landsofamerica.com (CoStar Group), and Adobe.com.

I'm a full-stack developer at heart, but what really drives me is designing and building internet architectures that are highly scalable, cost-effective, and fault-tolerant — solutions built to handle rapid growth and stay ahead of the curve.