Skip to main content

Command Palette

Search for a command to run...

Troubleshooting CORS for ORDS with Custom Domains

Published
3 min read
Troubleshooting CORS for ORDS with Custom Domains
M

With around 20 years on the job, Matt is one of the most experienced software developers at Pretius. He likes meeting new people, traveling to conferences, and working on different projects.

He’s also a big sports fan (regularly watches Leeds United, Formula 1, and boxing), and not just as a spectator – he often starts his days on a mountain bike, to tune his mind.

Ok, so you are here because you just like my blogs or you have his error

Access to fetch at 'https://leedsunited.com/ords/hrw/hr/employees/' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.

1. The initial CORS error from localhost

This started with a static HTML page served locally at http://127.0.0.1:5500 (e.g. VS Code Live Server … woo! Live Server rocks!), calling an ORDS endpoint at:

https://leedsunited.com/ords/hrw/hr/employees/

In the browser console, the error was:

Access to fetch at 'https://leedsunited.com/ords/hrw/hr/employees/' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.

The JavaScript fetch() failed with TypeError: Failed to fetch.

The issue was that the API was reachable, but the browser was refusing to expose the response because the CORS headers were missing. Basically it can access it, but just chucks it in the bin and gives me a nasty red error. It chucks it away because the CORS headers were missing

2. Verifying what the server actually returns

The next step was to confirm what the edge actually returned by using curl -i with an Origin header:

curl -i \
  -H "Origin: http://127.0.0.1:5500" \
  "https://leedsunited.com/ords/hrw/hr/employees/"

The response looked like this (truncated):

HTTP/2 200
date: ...
content-type: application/json
server: cloudflare
etag: "..."
# no Access-Control-Allow-Origin header here

This told two important things:

  • ORDS was returning data correctly (HTTP 200 + JSON body).

  • But there was no Access-Control-Allow-Origin header at all, so the browser just insta-rejects it … boo.

At this point I thought it was clearly a CORS configuration issue, not a connectivity or ORDS logic issue.

3. Checking ORDS module configuration

I next tried Tim Hall’s approach which is well worth a read.

Its basically allow certain origins to access the rest source module

begin 
  ords.set_module_origins_allowed(
    p_module_name     => 'oracle.example.hr',
    p_origins_allowed => 'http://localhost:5500');

  commit;
end;
/

It should work right?

Nope… I was still getting no CORS headers

HTTP/2 200
date: ...
content-type: application/json
server: cloudflare
etag: "..."
# no Access-Control-Allow-Origin header here

4. Introducing the proxy chain: Cloudflare + Nginx Proxy Manager

If you look closely at my set up. The request path is:

Browser -> Cloudflare (proxied) -> Nginx Proxy Manager -> ORDS

Since ORDS’ headers were not (or not reliably) making it out to the browser, I attempted to add CORS headers at the Nginx Proxy Manager layer, where the public traffic terminates.

In the NPM host for leedsunited.com, under the “Advanced” configuration, the following CORS headers were added:

add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Credentials' 'false' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Origin,Content-Type,Accept,Authorization' always;

This is a blanket approach: any origin is allowed (*), and credentials are explicitly disabled. Ask your favorite AI to adjust this to only allow custom Orgins

After saving and letting NPM reload Nginx, the same curl command was run again:

curl -i \
  -H "Origin: http://127.0.0.1:5500" \
  "https://leedsunited.com/ords/hrw/hr/employees/"

Now the response included the CORS headers - BINGO:

textHTTP/2 200
content-type: application/json
server: cloudflare
access-control-allow-origin: *
access-control-allow-credentials: false
access-control-allow-methods: GET, POST, OPTIONS
access-control-allow-headers: Origin,Content-Type,Accept,Authorization
...

This is exactly what the browser needed to treat the cross-origin response as accessible.

5. Validating the fix in the browser

With the new headers in place, the local HTML app was reloaded at http://127.0.0.1:5500:

  • The CORS error in the console disappeared.

  • The fetch() calls to /employees and related endpoints now succeeded.

  • The sections populated correctly.

ENJOY

What’s the picture? Western Flatts Cliff Park, Leeds. Visit Yorkshire