26

I know this has been addressed a lot of times on SO, but all the answers are mostly in the vein of "add a certain header to the server". In this case, the API (Shopify) works perfectly fine and can easily be accessed via curl.

I've tried this both with the Axios library and the Fetch API.

  • I've tried every value for referrer, mode, and referrerPolicy in the Fetch options.
  • I've confirmed my BasicAuth credentials are correct.
  • I've tried in multiple browsers.
  • I've tried from both localhost, localhost.com (set the value in my /etc/hosts), and from a server with a real domain name.

I can't understand why this would work perfectly fine in cURL, but not with fetch().

Here's a shortened version of my code:

const apiKey = 'mykey';
const apiPassword = 'mypass';
const apibase = 'https://my-shop-domain.myshopify.com/admin/';
const endpoint = 'locations.json';

var headers = new Headers({
   "Authorization": "Basic " + btoa( apiKey + ':' + apiPassword ),
});

    fetch( apibase + endpoint {
      method: 'GET',
      headers: headers,
      mode: 'no-cors',
      // cache: "no-store",
      // referrer: "client",
      // referrerPolicy: "origin",
      // credentials: 'include'
    }).then( resp => resp.json().then( resp => {

      console.log( resp );

    })).catch( err => {

      console.error(err);

    });

and the error that returns is

Access to fetch at 'https://my-shop-domain.myshopify.com/admin/locations.json' from origin 'https://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

If Shopify doesn't include the Access-Control-Allow-Origin header, why does the request work fine with cURL? There are node libraries and Ruby libraries to access the Shopify API, so it's hard to believe that they simply don't allow access from javascript at all.

So I guess my question is what can I do to access this API from with javascript?

JakeParis
  • 11,056
  • 3
  • 42
  • 65
  • per default curl doesn't send any extra headers, which you can confirm by running curl with -i option. If you send any arbitrary value in the Origin header along with the request, you should get the same error. – axel.michel Nov 27 '18 at 19:38
  • 2
    Running curl with `-i` option, and it works fine. I added Origin header as so: `curl -i -X GET -H "Authorization:Basic abcde12345" 'https://my-store.myshopify.com/admin/locations.json' -H "Origin:localhost"` and it still worked fine. – JakeParis Nov 27 '18 at 19:42
  • 8
    it's up to browser to check `Access-Control-Allow-Origin` header. cURL does not run such a check neither any other server-side software(e.g. NodeJS or Tomcat) does. – skyboyer Nov 27 '18 at 19:44
  • This clarified a lot for me: https://zemnmez.medium.com/if-cors-is-just-a-header-why-dont-attackers-just-ignore-it-63e57c323cef . Anyone struggling with the apparent contradiction of why curl works but not fetch, please read it :) – LGenzelis Apr 07 '21 at 00:04
  • The real issue that CORS solves is that without it, any domain could request any resource from any other domain, and they could do so *with the cookies already present in your browser*. So they could request `gmail.com/account`, and if you were logged in to gmail then they'd get to see your account page. CORS blocks this. (What I don't understand, though, is why browsers don't just not send cookies along with CORS-disallowed requests. Why disable the whole request altogether?) – BallpointBen Jan 12 '22 at 03:40
  • This question was closed, but I think that the way it's worded makes it distinct from the linked question. If I was searching for my problem, I would never find the linked question, because of the way that one is worded. Therefore I think this question should be re-opened, with a link to the other as having supplemental help. – JakeParis Jul 20 '22 at 12:48

2 Answers2

1

Why? explained:

The CORS policy is implemented in browsers to allow sharing resources between websites while preventing websites from attacking each other:

These policies only apply inside a browser. Presumably cURL works because it is making direct HTTP requests outside the context of a browser script. Which leads to how to work-around CORS restrictions...

Solutions:

3 Ways to Fix the CORS Error — and How the Access-Control-Allow-Origin Header Works explains how to bypass CORS restrictions. They all work by manipulating the request headers/origin:

  1. Browser extension. (Not sure if this still works in 2022. Only works if user installs browser extension.)
  2. 3rd party request proxy. (The proxy linked in the demo is now limited due to abuse.)
  3. Build your own proxy.

Realistically, option #3 is the only real solution. SvelteKit endpoints make it super simple to proxy requests.

Leftium
  • 16,497
  • 6
  • 64
  • 99
0

You have to use FormData instead of JSON.

    var data = new FormData();
    data.append('key', 'value');

    fetch('api', {
    method: 'POST',
    body: data,
    })
    .then(response => response.json())
    .then(data => {
    console.log(data);
    });
montassar
  • 16
  • 2