Search code examples
javascriptgoogle-cloud-platformcorsgoogle-cloud-storagegsutil

Setting cors on my GCP bucket not making a difference when accessing data from my bucket


I set all my GCP bucket items to be accessible to the public. I also set cors on my bucket using gsutil cors set cors-config.json gs://myBucketName. My cors config file looks like this: [{"origin": ["http://example.com"],"responseHeader": ["Content-Type"],"method": ["GET"],"maxAgeSeconds": 3600}]. Now I have two problems. The first one is when I try to access an audio file from my bucket and play it on my website I get the error Access to audio at 'http://publicIpAddr/fileName.mp4' from origin 'http://example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

NOTE: I am accessing the file via an IP address because I set up a load balancer with cloud cdn enabled which cached objects matching a path pattern I specified.

This is how I am accessing the audio file on my website:

JS

const audioElem = document.querySelector('#audioElem')
audioElem.crossOrigin = 'use-credentials';
audioElem.setAttribute('src', 'http://publicIpAddr/fileName.mp4')
audioElem.play()

The second problem is if I remove the audioElem.crossOrigin = 'use-credentials'; line from my JS code. The audio starts playing without an error. The issue is the audio plays from any domain regardless of it being specified as an allowed origin on my bucket cors options. Why is this happening? What am I missing? Thanks in advance.


Solution

  • TL;DR:

    If you've configured CORS correctly, just wait – even up to about two days.

    If it still doesn't work, re-check your config. Read below for details.

    Question 1: Bucket's CORS config not working

    I'm not exactly sure. (I'm actually having a similar issue and will report my findings.)

    If you have configured CORS correctly, the key is you have to wait several days before it actually takes effect.

    Exactly how much time, frankly I'm not sure, but it seems to be about two days. If it doesn't work by then, re-check your configuration. See the below list to make sure you've configured it correctly. Google is very strict, and having, e.g., invalid origin values for your CORS header will cause the header to just be left out (but Google won't tell you if they're valid).

    I'd recommend to start by checking to see if the Access-Control-Allow-Origin header is present when loading the audio directly from the storage bucket. If it is present there, but not on the request via your reverse proxy, then the problem is that the reverse proxy is not passing the header on.

    A few other minor things to check for:

    • Make sure CORS is applied for the correct bucket.
      • Commands for updating a bucket's CORS:
        • gcloud storage buckets update gs://bucket-name --cors-file="local/path/cors.json"
        • gsutil cors set local/path/cors.json gs://bucket-name
      • Commands for checking a bucket's CORS:
        • gcloud storage buckets describe gs://bucket-name --format="json(cors_config)"
        • gsutil cors get gs://bucket-name
    • Make sure your gcloud / gsutil command runs in the correct project.
      • Commands for switching projects:
        • gcloud init if not run already, otherwise
        • gcloud config set project project-name
      • Command for getting selected project:
        • gcloud config get project
    • Make sure you have valid CORS origins:
      • An origin is: protocol + domain + port (optional); nothing else.
        • Valid:
          • http://example.com:8080
          • https://example.net
        • Invalid:
          • https://something.com/ (trailing /)
          • htps://example.com (bad protocol)
          • http://example.com:65536 (port out-of-range)
          • http://example.com: (colon, no port)
          • http://Example.com (case-sensitive)
          • https://example.com:443 (does not match https://example.com)

    Question 2: CORS not needed for audio

    Not everything requires CORS. It mainly only applies to the XMLHttpRequest and fetch APIs.

    <script> tags, for instance, can be loaded from any domain without needing an Access-Control-Allow-Origin header. This is what made JSONP possible even before CORS existed.

    The same also applies to <audio> tags, <img> tags, and a number of other tags. The resources they load bypass any CORS policies.

    With that said, if you read over the details of the crossorigin attribute for the <audio> tag, it mentions the concept of tainted resources. A tainted resource, if used in some other way, taints what it's used on.

    For instance, if an image is loaded without respecting CORS, it is tainted. If it's then drawn on a <canvas> the canvas also becomes tainted. Tainted canvases then have additional restrictions. e.g., context.getImageData / canvas.toDataURL will no longer be allowed.