Server

Cross-Origin Resource Sharing (CORS)

Updated: December 2, 2024

If you perform cross-domain requests from any JavaScript client to access WebEngine resources or Automation APIs, there's a chance that your browser will block it. CORS allows you to communicate with Nuxeo from another domain using XMLHttpRequests.

Nuxeo uses a filter to handle those cases. It's based on Vladimir Dzhuvinov's universal CORS filter, and allows you to configure on which URLs cross-origin headers are needed. You'll be able to configure each URL independently.

Configuration

Here is the list of all [optional] contribution attributes.

Attribute name Description / Possible Values Default value
allowGenericHttpRequests If false, only valid and accepted CORS requests are allowed (strict CORS filtering).
true | false
true
allowOrigin The whitespace-separated list of origins that the CORS filter must allow.
* | http://example.com http://example.com:8080
*
allowSubdomains If true, CORS filter will allow requests from any origin which is a sub-domain origin of the allowed origins.
true | false
false
supportedMethods The list of the supported HTTP methods.
* | comma-separated list of HTTP methods
GET, POST, HEAD, OPTIONS
supportedHeaders The names of the supported author request headers.
* | comma-separated list of headers
*
exposedHeaders The list of response headers other than simple response headers that the browser should expose to the author of the cross-domain request through the XMLHttpRequest.getResponseHeader() method.
* | comma-separated list of headers
*
supportsCredentials Indicates whether user credentials, such as cookies, HTTP authentication or client-side certificates, are supported.
true | false
true
maxAge Indicates how long the results of a preflight request can be cached by the web browser, in seconds.
integer
-1

Verifying That the Contribution Is Taken into Account

To debug your CORS configuration, use a cURL request and look at the response. If you haven't blocked the OPTIONS method, you should test with the preflight request for an expected POST request:

Simulate preflight request

curl --verbose -H "Origin: http://www.nuxeo.com" -H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: X-Requested-With" -X OPTIONS http://NUXEO_SERVER/nuxeo/site/foobar/upload

With the default configuration, preflight's response looks like this:

Default response

< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Access-Control-Allow-Origin: http://www.nuxeo.com
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Methods: HEAD, POST, GET, OPTIONS
< Access-Control-Allow-Headers: X-Requested-With
< Content-Length: 0 

The Access-Control-Allow-* headers contain the expected values.

Examples

Here is an example of the simplest contribution, allowing cross-domain requests on the whole foobar site:

Simplest contribution

<extension target="org.nuxeo.ecm.platform.web.common.requestcontroller.service.RequestControllerService" point="corsConfig">
    <corsConfig name="foobar" supportedMethods ="GET,POST,HEAD,OPTIONS,DELETE,PUT">
      <pattern>/nuxeo/.*</pattern>
    </corsConfig>
</extension>

A fooly complete contribution would look like:

Fooly contribution

<extension target="org.nuxeo.ecm.platform.web.common.requestcontroller.service.RequestControllerService" point="corsConfig">
    <corsConfig name="fooly" allowGenericHttpRequests="true"
      allowOrigin="http://example.com http://example.com:8080"
      allowSubdomains="true" supportedMethods="GET"
      supportedHeaders="Content-Type, X-Requested-With"
      exposedHeaders="X-Custom-1, X-Custom-2"
      supportsCredentials="false" maxAge="3600">
      <pattern>/fooly/site/.*</pattern>
    </corsConfig>
</extension>