yes

AWS CloudFront: Access to script has been blocked by CORS policy

Access to script at 'https://cf.yourdomain.com/script.js' from origin 'https://yourdomain.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Looks familiar? Read on!

AWS CloudFront is an excellent CDN service when hosting your static assets. If you're referencing your scripts with the crossorigin="anonymous" turned on, then the browser sends through an additional header: Origin: https://yourdomain.com. Now, the response has to include the header Access-Control-Allow-Origin, or otherwise you'll get the error above.

"But it always works with S3?!" Yes, S3 doesn't do any caching for you, which will always get you the correct headers. With CloudFront, the first request gets cached with the headers requested. That means if you (by you I mean the browser) didn't include the Origin header in the initial request, all the subsequent ones fill not have the Access-Control-Allow-Origin.

You can test that by uploading a new script and firing two curl requests. First without the origin header:

curl -I "https://cf.yourdomain.com/script2.js"

And then with the origin header

curl -I -H "origin: https://yourdomain.com" "https://cf.yourdomain.com/script2.js"

The first response should have the header x-cache: Miss from cloudfront and the second one should say Hit from cloudfront. Neither of the responses has Access-Control-Allow-Origin set because the first request cached it without.

How to fix that?

There are two ways to fix that:

1) Instruct your CloudFront distribution to vary the cache key based on the Origin header: Log into your AWS Console, go to your CF distribution > Behaviours > Edit and whitelist the header Origin.

2) A better alternative is to always include the origin header and pass it to the distribution origin itself. This avoids creating multiple cache keys and doesn't require the client to send the Origin header. This can be configured from Edit Origin\ > Origin Custom Headers:

Header Name: origin
Value: all

Note that the name has to be lowercase.

You should have two separate cache hits now. You can test that by creating a new file and firing those curl requests again.