How to Enable CORS for ORDS APIs

Let web applications on other origins call your ORDS APIs, restrict a module to the origins you trust, and test preflights.

A web page can call an API on another origin only if the API allows it through CORS headers. ORDS answers cross-origin requests for REST modules, and each module can limit the origins it accepts. This guide checks the default behavior, restricts a module to one web application, and shows the preflight and refusal responses.

Before You Start

You need ORDS installed and running against your database, and a schema to work in. The examples use NIMBUS, the sample schema of a fictional airline, which you can install with the scripts in the setup/nimbus folder of the Oracle Database 26ai code repository on GitHub. The schema comes from Oracle Database 26ai SQL and PL/SQL Book.

ORDS in the examples answers at https://localhost:8443/ords/, and NIMBUS is REST-enabled with the URL alias nimbus. Replace the host and port with your own ORDS address. The curl commands use -k because the test server has a self-signed certificate; leave it out when your certificate is trusted. JSON responses are formatted for reading; ORDS returns them on one line.

The examples use the network module from How to Create a REST Module, Template, and Handler with ORDS.DEFINE_MODULE. curl sends the Origin header that a browser would send.

Syntax

ords.set_module_origins_allowed(p_module_name     => 'module',
                                p_origins_allowed => 'https://app.example.com');   -- comma-separated
ords.set_module_origins_allowed(p_module_name => 'module', p_origins_allowed => null);  -- any origin

The Default: Any Origin

Without a list, the module answers any origin and echoes it back:

Example:

curl -k -D - -o /dev/null -H "Origin: https://app.nimbus.example" \
  https://localhost:8443/ords/nimbus/network/routes/7

Output (CORS headers):

HTTP/1.1 200 OK
Vary: Origin
Access-Control-Expose-Headers: Content-Type, ETag, Vary, Access-Control-Allow-Origin, Access-Control-Allow-Credentials
Access-Control-Allow-Origin: https://app.nimbus.example
Access-Control-Allow-Credentials: true

Allow One Origin

Example:

begin
  ords.set_module_origins_allowed(p_module_name     => 'network',
                                  p_origins_allowed => 'https://app.nimbus.example');
  commit;
end;
/
select name, origins_allowed from user_ords_modules where name = 'network';

Output:

PL/SQL procedure successfully completed.

NAME       ORIGINS_ALLOWED
__________ _____________________________
network    https://app.nimbus.example

The allowed origin still gets its CORS headers:

Output:

== allowed origin
HTTP/1.1 200 OK
Vary: Origin
Access-Control-Expose-Headers: Content-Type, ETag, Vary, Access-Control-Allow-Origin, Access-Control-Allow-Credentials
Access-Control-Allow-Origin: https://app.nimbus.example
Access-Control-Allow-Credentials: true

Any other origin is refused:

Output:

== other origin
HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
Content-Length: 829

{
    "code": "Forbidden",
    "title": "Forbidden",
    "message": "The request cannot be processed because it failed cross origin request validation ",
    "o:errorCode": "ORDS-13002",
    "cause": "This resource does not support Cross Origin Sharing requests, or the request Origin is not authorized to access this resource. ",
    "action": "If ords is being reverse proxied ensure the front end server is propagating the host name, scheme and port correctly. If using mod_proxy ensure ProxyPreserveHost is set to On. If using SAML with Oracle APEX, ensure security.externalSessionTrustedOrigins is correctly configured. If using a RESTful Service ensure the Origins Allowed value is correctly configured",
    "type": "tag:oracle.com,2020:error/Forbidden",
    "instance": "tag:oracle.com,2020:ecid/FZ_NRV23BO9kRmS8uJT4cw"
}

The Preflight Request

Before some requests, browsers send an OPTIONS preflight asking which methods are allowed:

Example:

curl -k -D - -o /dev/null -X OPTIONS \
  -H "Origin: https://app.nimbus.example" \
  -H "Access-Control-Request-Method: GET" \
  https://localhost:8443/ords/nimbus/network/routes/7

Output:

== preflight
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://app.nimbus.example
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 3600
Access-Control-Allow-Methods: GET

ORDS lists the methods the template has handlers for, GET here, and lets the browser cache the answer for an hour.

Remove the Restriction

Example:

begin
  ords.set_module_origins_allowed(p_module_name     => 'network',
                                  p_origins_allowed => null);     -- back to any origin
  commit;
end;
/

Things to Know

  • CORS is enforced by browsers: server-side clients such as curl without an Origin header are not affected, so CORS is not access control.
  • List exact origins, with scheme and port, such as https://app.example.com:8443.
  • As with other ORDS changes, the new list takes effect after ORDS refreshes its cache, a few seconds in the test.

Related Guides

Conclusion

ORDS REST modules answer cross-origin requests from any origin until you restrict them with ORDS.SET_MODULE_ORIGINS_ALLOWED. List the web applications that may call the API, test with an Origin header and a preflight, and use privileges, not CORS, to control access.

Get more Vinish.dev tutorials on Google

See my articles more often when you search Google.

Vinish Kapoor
Vinish Kapoor

An Oracle ACE, author of four books on Oracle APEX, SQL and PL/SQL, and Oracle Forms, and a software developer building Oracle database applications since 2001.

guest

0 Comments
Oldest
Newest Most Voted