CORS in Magento 2.2.x

On upgrading our own website to Magento 2.2.0 we encountered various console errors due to cross origin (see examples below) which turned out to be due to our use of a CDN on a different domain. We were able to solve this with a tweak to our CDN setup and by adding some new rules to the nginx configuration, detailed below.

The error messages

These are a summary of the errors appearing in the console as a symptom of this new issue:

... OPTIONS ... 405 ()
Uncaught SyntaxError: Unexpected end of JSON input
Response for preflight has invalid HTTP status code 405
Request header field x-requested-with is not allowed by Access-Control-Allow-Headers in preflight response.
Failed to load ... Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin ... is therefore not allowed access. The response had HTTP status code 405.
Access to Font at 'xxx' from origin 'xxx' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'xxx' is therefore not allowed access.
Failed to load xxx: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'xxx' is therefore not allowed access.
Failed to load xxx: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'xxx' is therefore not allowed access.
Failed to load xxx: Request header field x-requested-with is not allowed by Access-Control-Allow-Headers in preflight response.

Web Server Configuration

The solution is relatively simple, you just need to add some special handling of cross origin requests and pre-flight OPTIONS requests to your web server configuration to allow the pre-flight requests through.

This will allow all origins to access your resources:

# Note: for 'Access-Control-Allow-Origin' we use '*' instead of 'https://www.your-website.co.uk'
# to be absolutely sure that these assets can be served to any origin, since we have a mixture of CDN,
# frontend url and admin url. We want to mitigate the risk of these PUBLIC assets not being served.

add_header 'Access-Control-Allow-Origin' '*' 'always';

if ($request_method = 'OPTIONS') {
    add_header 'Access-Control-Allow-Origin' '*' 'always';
    add_header 'Access-Control-Allow-Headers' 'x-requested-with' 'always';
    add_header 'Access-Control-Max-Age' 86400 'always';
    add_header 'Content-Length' 0 'always';
    return 204;
}

This same code needs to be added to each of your location blocks within /static, so we recommend adding this as a new file magento2-cors.conf and using include to prevent duplicating the same rules over and over, eg:

location /static/ {
    location ~* \.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2)$ {
        add_header X-Frame-Options "SAMEORIGIN";
        include /etc/nginx/magento2-cors.conf;
    }
    
    location ~* \.(zip|gz|gzip|bz2|csv|xml)$ {
        add_header X-Frame-Options "SAMEORIGIN";
        include /etc/nginx/magento2-cors.conf;
    }
    
    add_header X-Frame-Options "SAMEORIGIN";
    include /etc/nginx/magento2-cors.conf;
}

Use '*' since these assets are PUBLIC

This article previously contained an approach to have the request determine the origin via something like the following. The following snippet is no longer recommended.

# Do NOT use this approach any more:
if ($http_origin ~* "^https?://www\.your-website\.co\.uk$" ) {
    add_header 'Access-Control-Allow-Origin' $http_origin 'always';
}

CDN Configuration

Also ensure your CDN is configured to allow OPTIONS requests through and to be cached, as by default CDN may only allow GET and POST.

We're here to help!

As always if you need some assistance or would like us to do this for you, please please get in touch.

For more information on setting up AWS CloudFront CDN with your Magento website, please see our tutorial here.