Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

POSTing to external API throws CORS but it works from Postman

Tags:

I am using the imgur api to upload images via a node js app.

I am converting images to base64 strings and sending them via Postman works great.

I use node-fetch to make api calls.

const fetch = require('node-fetch') ... async uploadImage(base64image) {         try {             const url = 'https://api.imgur.com/3/image'             const res = await fetch(url,                 {                     method: 'POST',                     body: { image: base64image },                     headers: {                         'content-type': 'application/json',                         'Authorization': 'Client-ID [my-client-id]',                         'Access-Control-Allow-Headers': 'Content-Type, Authorization, Access-Control-Allow-Headers',                         'Access-Control-Allow-Methods': 'POST',                     }                 }             )              console.log(res)         } catch(err) {             console.log(err)         }     } 

Error: Access to fetch at 'https://api.imgur.com/3/image' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field Access-Control-Allow-Headers is not allowed by Access-Control-Allow-Headers in preflight response.

I have tried many 'Access-Control-Allow-xxx' headers but none of them worked..

I assume it must be something simple that I am missing. I have been stuck on this for hours please help me.

like image 993
Cristian G Avatar asked Dec 08 '18 16:12

Cristian G


People also ask

Why does CORS work on postman but not browser?

The CORS standard is a client-side standard, implemented in the browser. So it is the browser which prevent the call from completing and generates the error message - not the server. Postman does not implement the CORS restrictions, which is why you don't see the same error when making the same call from Postman.

Does postman ignore CORS?

Postman simply doesn't care about CORS headers. So CORS is just a browser concept and not a strong security mechanism. It allows you to restrict which other web apps may use your backend resources but that's all.

What is CORS error in Postman?

Note: The CORS error generally happens due to browser limitations regarding resources shared between different internet domains. Please refer to this blog post for more information about CORS and how the Postman Desktop Agent works.

What is a CORS issue?

The CORS behavior, commonly termed as CORS error, is a mechanism to restrict users from accessing shared resources. This is not an error but a security measure to secure users or the website which you are accessing from a potential security bleach.


2 Answers

Browser restricts HTTP requests to be at the same domain as your web page, so you won't be able to hit imgur api directly from the browser without running into CORS issue.

I am converting images to base64 strings and sending them via Postman works great.

That's because Postman is not a browser, so is not limited by CORS policy.

I have tried many 'Access-Control-Allow-xxx' headers but none of them worked..

These headers must be returned by the server in response - in your case by the imgur server. You can't set them in the request from browser, so it'll never work.

Error: Access to fetch at 'https://api.imgur.com/3/image' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field Access-Control-Allow-Headers is not allowed by Access-Control-Allow-Headers in preflight response.

Possible solutions to your problem:

  1. If you have access to the backend api you can set the "Access-Control-Allow-Origin" header on the server and let your app access the api - but as you won't have access to the imgur server - you probably can't do that.

  2. Disable CORS in the browser - you can use a plugin like: https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=en. This workaound should be fine for development. The plugin will disable your CORS settings and you will be able to hit imgur apis.

  3. The third solution is using a proxy. You can setup a small node server using express. You will then hit your own node server, which in turn will hit the imgur api. As node server is not a browser environment, it won't have any CORS issue and you will be able to access imgur API that way. This is also the reason you were able to hit the API from Postman without any issues. As Postman is not a browser environment, it's not limited by CORS policy.

like image 127
Jatin Gupta Avatar answered Oct 03 '22 18:10

Jatin Gupta


That's because Access-Control-Allow-Headers, Access-Control-Allow-Methods are the headers that is used by the server. The server appends the header by a middleware.

Now, imagine in the server(in this below example an express server) with CORS enabled this kind of (default) headers are getting set:

app.use(function (req, res, next) {     res.header('Access-Control-Allow-Origin', '*');     res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');     res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With, Accept'); }); 

And you are sending Access-Control-Allow-Headers from the client side, and server sees that as a header that is not whitelisted.

So, in headers just use these:

headers: {     'content-type': 'application/json',     'Authorization': 'Client-ID [my-client-id]' } 

It should work fine.

Btw, I think it is working with postman because:

  • Postman cannot set certain headers if you don't install that tiny postman capture extension.
  • Browser security stops the cross origin requests. If you disable the chrome security it will do any CORS request just fine.

Also, according to this:

I believe this might likely be that Chrome does not support localhost to go through the Access-Control-Allow-Origin -- see Chrome issue

To have Chrome send Access-Control-Allow-Origin in the header, just alias your localhost in your /etc/hosts file to some other domain, like:

127.0.0.1   localhost yourdomain.com 

Then if you'd access your script using yourdomain.com instead of localhost, the call should succeed.

Note: I don't think the content type should be application/json it should be like image/jpeg or something. Or maybe don't include that header if it doesn't work.

like image 42
Aritra Chakraborty Avatar answered Oct 03 '22 16:10

Aritra Chakraborty