CORS (Cross-Origin Resource Sharing)

Cross-Origin Resource Sharing is a browser technology specification that defines ways for a web server to allow its resources to be accessed by a browser application from a different origin domain. Such access would otherwise be forbidden by the same origin policy. CORS defines a way in which the browser and the server can interact to determine whether to allow the cross-origin request. It’s a compromise that allows greater flexibility, but is more secure than simply allowing all such requests.

The CORS standard works by adding new HTTP headers that allow servers to serve resources to permitted origin domains. Browsers support these headers and enforce the restrictions they establish. Additionally, for HTTP request methods that can cause side-effects on user data (in particular, for HTTP methods other than GET, or for POST usage with certain MIME types) the specification mandates that browsers “pre-flight” the request, soliciting supported methods from the server with an HTTP OPTIONS request header, and then, upon “approval” from the server, sending the actual request with the actual HTTP request method. Servers can also notify clients whether “credentials” (including Cookies and HTTP Authentication data) should be sent with requests.

CORS can be used as a modern alternative to the JSONP pattern. While JSONP supports only the GET request method, CORS also supports other types of HTTP requests. Using CORS enables a web programmer to use *XMLHttpRequest*, which supports a better error handling than JSONP. CORS is supported by most modern web browsers. However, JSONP works on legacy browsers that preclude CORS support.

CORS and the Open Commerce API 

The Open Commerce API supports the CORS specification.

If an API request contains an Origin header, the origins in the header are verified against a list of allowed origins. The list can be configured in Business Manager Open Commerce API Settings on a per site and client application basis. If all the origins in the header match the configured origins, the API confirms the origins by returning all allowed origins in response header *Access-Control-Allow-Origin*. Additionally, the API returns the response header *Access-Control-Allow-Credentials* with value “true”, which notifies the client to send also cookies. If an origin isn’t defined in the allowed origins list, the API does NOT add the *Access-Control-Allow* headers to the response. This is true for GET and HEAD requests. For PATCH, POST, PUT, and DELETE requests, the API returns a 401 fault of type *UnauthorizedOriginException* and ensures that there’s no processing on the server side.

“Preflighted” requests first send an HTTP OPTIONS request header to the resource on the other domain; this determines whether the actual request is safe to send. Cross-site requests are preflighted because the requests may affect user data. In particular, a request is preflighted if it uses methods other than GET or POST. A request is also preflighted if the POST method is used to send request data with a Content-Type other than *application/x-www-form-urlencoded, multipart/form-data*, or *text/plain*?for example, if the POST request sends an XML payload to the server using *application/json, application/xml* or *text/xml*, the request is preflighted.

Configure Allowed Origin(s) 

To configure allowed origins for the Open Commerce API, perform the following steps:

  1. In Business Manager, select Administration > Site Development > Open Commerce API Settings.
  2. Select a site for which you want to configure allowed origins.
  3. In the text field, you configure the property allowed_origins per client application in the JSON document, as described below.
1{
2  "_v" : "24.5",
3  "clients":
4  [
5    {
6      "allowed_origins":["http://foo.com","https://secure.foo.com:8888"],
7      "client_id":"[your_own_client_id]",
8      "resources":
9      [
10        {
11          "resource_id":"/customers/auth",
12          "methods":["post"],
13          "read_attributes":"(**)",
14          "write_attributes":"(**)"
15        },
16        {
17          "resource_id":"/baskets",
18          "methods":["post"],
19          "read_attributes":"(**)",
20          "write_attributes":"(**)"
21        },
22        ...
23      ]
24    }
25  ]
26}

The ’*’ wildcard isn’t supported.

Note

Examples 

Example 1: GET request with unknown origin - no *Access-Control-Allow* headers in response; browser should reject the response by forcing same origin policy.

1REQUEST:
2GET /dw/shop/v24_5/products/123/availability HTTP/1.1
3Host: example.com
4Origin: http://bar.com
5
6RESPONSE:
7HTTP/1.1 200 OK
8Content-Length: 67
9Content-Type: application/json; charset=UTF-8
10Cache-Control: max-age=60,must-revalidate
11
12{
13  "id":"123",
14  "name":"Shirt",
15  "orderable":true
16}

Example 2: GET request with known origin - *Access-Control-Allow* headers in response; modern browsers should make the response content available.

1REQUEST:
2GET /dw/shop/v24_5/products/123/availability HTTP/1.1
3Host: example.com
4Origin: http://foo.com
5
6RESPONSE:
7HTTP/1.1 200 OK
8Access-Control-Allow-Origin: http://foo.com
9Access-Control-Allow-Credentials: true
10Access-Control-Expose-Headers: location,x-dw-version-status
11Content-Length: 67
12Content-Type: application/json; charset=UTF-8
13Cache-Control: max-age=60,must-revalidate
14
15{
16  "id":"123",
17  "name":"Shirt",
18  "orderable":true
19}

Example 3: POST request with unknown origin: Pre-flight OPTIONS request contains no confirming *Access-Control-Allow* headers; browsers skip the second request.

1REQUEST:
2OPTIONS /dw/shop/v24_5/baskets HTTP/1.1
3Host: example.com
4Origin: http://bar.com
5Access-Control-Request-Method: POST
6Access-Control-Request-Headers: Content-Type
7
8RESPONSE:
9HTTP/1.1 204 No Content
10Allow: POST

Example 4: POST request with known origin: Pre-flight OPTIONS request has confirming *Access-Control-Allow* headers in response; browsers execute the second request.

1REQUEST 1:
2OPTIONS /dw/shop/v24_5/baskets HTTP/1.1
3Host: example.com
4Origin: http://foo.com
5Access-Control-Request-Method: POST
6Access-Control-Request-Headers: Content-Type
7
8RESPONSE 1:
9HTTP/1.1 204 No Content
10Access-Control-Allow-Methods: POST
11Access-Control-Max-Age: 86400
12Access-Control-Allow-Origin: http://foo.com
13Access-Control-Allow-Credentials: true
14Access-Control-Allow-Headers: Content-Type
15Allow: POST
16
17REQUEST 2:
18POST /dw/shop/v24_5/baskets HTTP/1.1
19Host: example.com
20Origin: http://foo.com
21Authorization:Bearer eyJfdiI6IjXXXXXX.eyJfdiI6IjEiLCJleHAXXXXXXX.-d5wQW4c4O4wt-Zkl7_fiEiALW1XXXX
22Content-Type: application/json
23Content-Length: 67
24
25{
26  "product_id" : "456",
27  "quantity" : 1.00
28}
29
30RESPONSE 2:
31HTTP/1.1 200 OK
32Access-Control-Allow-Origin: http://foo.com
33Access-Control-Allow-Credentials: true
34Access-Control-Expose-Headers: location,x-dw-version-status
35Content-Type: application/json;charset=UTF-8
36Cache-Control: max-age=0,no-cache,no-store,must-revalidate
37Content-Length: 158
38
39{
40  "_v" : "24.5",
41  "_resource_state" : "ba4e84383e1790597e49eeee34b201633d80ed3f499992f5af11d639dd903a36"
42  "currency" : "USD",
43  "product_sub_total" : 40.00,
44  "product_total" : 40.00,
45  "shipping_total" : null,
46  "tax_total" : null,
47  "order_total" : null,
48  "product_items" :
49  [
50    {
51      "product_id" : "456",
52      "item_text" : "Product foo",
53      "quantity" : 1.00,
54      "product_name" : "foo",
55      "base_price" : 40.00,
56      "price" : 40.00
57    }
58  ]
59}

Attention!

The Open Commerce API (OCAPI) is now deprecated. The provisions described in our versioning and deprecation policy fully apply. For all new projects and major refactoring work, use B2C Commerce API (SCAPI) as the default REST API. For additional details, refer to Why Use SCAPI Instead of OCAPI.

DID THIS ARTICLE SOLVE YOUR ISSUE?
Let us know so we can improve!