---
schema_version: "1"
id: 089b76150bef88b4ff4667abab2201eae45273f4d9492dbb761d1bb4fe907038
title: CORS in SCAPI
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/commerce-cloud/commerce-api/guides/scapi-cors.md
canonical_url: https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/scapi-cors.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: 2fcc671705f26ab30880091ba32096669b026a30752712d285ffd456ed41ebcb
products:
  - Composable Storefront
  - Salesforce APIs
---
# CORS in SCAPI

CORS allows a web service to establish exceptions to the same-site policy that browsers normally enforce. Without CORS, browser access to resources on other servers is possible, but the browser prevents the response from being accessed and processed by the script.

When a browser requests a resource from a site whose domain is different from the site where the script is executed, an `Origin` header is added to the request. A server supporting CORS returns the response header `Access-Control-Allow-Origin`, which contains a list of origins that are allowed to use the endpoint. If the current origin is not part of the list, the browser prevents the content from being accessed.

The following image shows the request flow for a server named `bar.com` that supports CORS:

![Cross-Origin Resource Sharing (CORS) request flow and validation process](https://developer.salesforce.com/docs/media/commerce-api/cors-overview.png)

Browsers automatically make preflight requests before a modifying request is executed. Each preflight request is made as an `OPTIONS` request with the `Origin` header and the `Access-Control-Request-Method` header.

The resulting CORS response contains the `Access-Control-Allow-Methods` header, which lists the methods that the client is allowed to execute from the origin. It also contains the `Access-Control-Max-Age` header, which tells the browser how long (in seconds) it can cache the preflight result and reuse it for subsequent requests without repeating the preflight.
The modifying request itself is then only executed if the preflight request is successful, as shown in the following example request flow:

![CORS preflight request process and header validation](https://developer.salesforce.com/docs/media/commerce-api/cors-preflight-request.png)

## Configure CORS in SCAPI

As of B2C Commerce 24.8, SCAPI adheres to the CORS standard and security best practices, and supports CORS requests for all Data and Shopper API endpoints.

Preflight (OPTIONS) requests are also supported.

If no configuration is provided, CORS is not active. To configure CORS in SCAPI, use the [CORS API](https://developer.salesforce.com/docs/commerce/commerce-api/references/cors?meta=Summary).

The configured list of aliases is automatically enriched with all known default names and site aliases. You do not need to explicitly configure them for CORS.

**note:** For security reasons, wildcards (\*) are not supported, and the returned `Access-Control-Allow-Origin` header does not contain the full list of allowed origins. It only contains the single origin that was submitted with the current request’s `Origin` header.

The configuration of allowed CORS origins is unique to each environment and is not replicated between environments. The configuration of allowed origins is done per client ID and site, which means:

- You can maintain separate lists of allowed origins for different applications.
- You cannot have individual API or endpoint configurations.

The CORS API requires an AM OAuth token with the scope `sfcc.cors-preferences.rw`. When you send a new CORS configuration with a PUT request, the response mirrors the stored configuration, for example:

```json
{
  "corsClientPreferences": [
    {
      "clientId": "12345678-90ab-cdef-fedc-ba0987654321",
      "origins": [
        "http://foo.com",
        "https://foo.bar.com",
        "myapp://example.com"
      ]
    }
  ]
}
```

Allowed URLs can contain any scheme and are not limited to HTTP and HTTPS. Each origin must adhere to the http-style format of `<scheme>://(<subdomain>.)<domain>(.<tld>)` and must not contain port or path information.

The port is not part of the configuration. If the origin domain is part of the allowlist, all ports are accepted by SCAPI CORS.

To enable CORS for a client without specifying custom origins, configure the client and site with an empty origin list. Known domain names and aliases still apply.

```json
{
  "corsClientPreferences": [
    {
      "clientId": "12345678-90ab-cdef-fedc-ba0987654321",
      "origins": []
    }
  ]
}
```

### CORS Responses

A CORS request, for example: a GET, PUT, POST, DELETE, or HEAD request, yields the same result as a typical request:

If a request contains a valid `Origin` header, the response contains the following headers:

```http
Access-Control-Allow-Origin
Access-Control-Allow-Headers (only if Access-Control-Request-Headers was included in the request)
Access-Control-Allow-Credentials (always true)
```

If a request contains an invalid `Origin` header, these response headers are simply missing, with no other changes.

Note: This behavior is different from OCAPI CORS where a manipulating request with an invalid origin results in a `401` status code and the message `Unauthorized Origin`.

For preflight requests with a valid endpoint, the server returns a `200 Success` status with the following headers:

```http
Access-Control-Allow-Origin
Access-Control-Allow-Methods
Access-Control-Max-Age
Access-Control-Allow-Headers (only if Access-Control-Request-Headers was included in the request)
Access-Control-Allow-Credentials (always true)
```http

The `Access-Control-Max-Age` header is set to `600` seconds (10 minutes). Browsers cap this value to their own maximum (for example, 7200 seconds in Chromium-based browsers and 86400 seconds in Firefox).

If the endpoint is invalid, the call will return a `404 Not Found` status.

### Example Responses

```markdown
REQUEST:
GET `https``:``//{shortCode}.api.commercecloud.salesforce.com/product/shopper-products/v1/organizations/{organizationId}/products/{productId}`
Origin: https://foo.com

RESPONSE: 200
{
    "id": "{productId}",
    ...
}
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://foo.com
```

```markdown
REQUEST:
GET `https://{shortCode}.api.commercecloud.salesforce.com/product/shopper-products/v1/organizations/{organizationId}/products/{productId}`
Origin: https://foobar.com

RESPONSE: 200
{
    "id": "{productId}",
    ...
}
(no CORS headers)
```http

```markdown
REQUEST:
OPTIONS `https``:``//{shortCode}.api.commercecloud.salesforce.com/product/shopper-products/v1/organizations/{organizationId}/products/{id}`
Origin: https://foo.com
Access-Control-Request-Method: GET

RESPONSE: 200
(no Body)
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, OPTIONS
Access-Control-Allow-Origin: https://foo.com
Access-Control-Max-Age: 600
```http

```markdown
REQUEST:
OPTIONS `https://{shortCode}.api.commercecloud.salesforce.com/product/shopper-products/v1/organizations/{organizationId}/products/{id}`
Origin: https://foo.com
Access-Control-Request-Method: GET

RESPONSE: 200
(no Body)
(no CORS headers)
```

### Constraints

Custom APIs are not currently supported.
