1

I'm building a simple React app and want to display TripAdvisor photos of a specified city. TripAdvisor has an API to do this, and when I make a request through Postman, no issue. I get the data perfectly. When I make the request through a fetch call within my React app, I get a seemingly classic CORS error:

Access to fetch at 'https://api.content.tripadvisor.com/api/v1/location/[...]' from origin 'http://localhost:3000' 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.

My understanding is that this is because I'm making a call from localhost to tripadvisor.com. The mismatch is setting off the CORS error in my browser (Chrome). I get that.

What I don't understand is how anyone uses this API then. My understanding is that the issue is that TripAdvisor's not sending the required header ("Access-Control-Allow-Origin" with the value of my specified domain/IP address).

The 7 headers they send back are: Date, Content-Type, Content-Length, Connection, x-amzn-RequestId, x-amz-apigw-id, X-Amzn-Trace-Id.

Do I need to set up a proxy server as a middleman to bypass the CORS mismatch?

Is everyone who uses this API doing that?? That seems crazy to me.

All insight welcome.

2 Answers 2

1

Let us get to the root of this

The web server defines the CORS configuration

And your browser enforces CORS based on what headers it has received from the server when it fetched the website.

Access-Control-Allow-Origin header tells the browser which origin can initiate a HTTP API call to the web server. You can read about it in detail here

CORS is applicable only in case when web browsers are initiating requests, The browser blocks request if it is not according to policy. This is not applicable to Postman or web servers.

You are getting an error because the CORS policy of Tripadvisor is such that it does not allow requests from http://localhost:3000

Now one potential solution to this

  1. Lets say your website is hosted at myDomain.com
  2. Run your proxy at myDomain.com, Your website will call the proxy at myDomain.com and it will be a same origin HTTP API call
  3. Your web server / proxy running at myDomain.com will in return call Tripadvisor APIs
1

Usually, you should not make authenticated third-party API requests directly from your app running in the browser. This is because anybody using your app can go to the network tab of their browser, copy the API key or other credentials identifying your app to the API from one of the requests, and use it to make (potentially malicious) requests against the API on behalf of your app.

Conversely, this means that if Tripadvisor were to set the Access-Control-Allow-Origin header and thus allow these kinds of requests, it would expose its users to a potential security threat. So it's very plausible that this is why they didn't set the header, but the exact reasoning is unknown.

Usually, you communicate with third-party APIs through a backend server deployed alongside your frontend app. I think you're referring to this as a "proxy" here. The idea is to securely store all credentials needed for third-party API calls on the server side instead of the app code where everybody can see them. Also, it hides the details of the request logic for those calls from the app, which has no business knowing about this kind of stuff to begin with.

2
  • Thanks! I think I get why I was confused now--I did not have the right mental model for separation of front/backend. I thought these APIs and the frontend needed to talk to each other directly (probably since that's how I've been testing it as I go), but now I'm realizing that's fundamentally wrong. Since I'll use Firebase for the backend, all my other third-party API calls should go through that using their server-side cloud functions, Callables. That's what will play the role of my "proxy" server as you pointed out. Thanks for breaking it down. Hopefully I've got it correct now...
    – achalla
    Commented May 7 at 11:11
  • @achalla Yes, absolutely, that sounds like you got it down! You set up your third-party calls in Cloud Functions as an intermediate layer and invoke those functions (essentially the first-party API of your app now) instead of the third-party API directly. For Cloud Functions, you would also want to store the Tripadvisor API key in a secret inside Cloud Secret Manager. You can then use the Firebase SDK in your Cloud Function to read the API key, as detailed here: t.ly/RD_H1 If you have any more questions, just let me know
    – TheKvist
    Commented May 7 at 12:16

Not the answer you're looking for? Browse other questions tagged or ask your own question.