USDA / USDA-APIs

Do you have feedback, ideas, or questions for USDA APIs? Use this repository's Issue Tracker to join the discussion.
www.usda.gov/developer
107 stars 16 forks source link

CORS XMLHttpRequest from localhost sets two Access-Control-Allow-Origin headers #79

Closed seanharr11 closed 4 years ago

seanharr11 commented 4 years ago

When making an XMLHttpRequest from a browser client served from localhost, the USDA API server sets the Access-Control-Allow-Origin header twice, once to * and once to localhost:3000.

This violates the CORS spec (the header can only be set once), and the browser throws the following CORS error preventing the web app from reading the result of the request:

Access to XMLHttpRequest at 'https://api.nal.usda.gov/fdc/v1/search?generalSearchInput=a&api_key=oDMbMNfX1gaeV7gaU6qpvpRaWRszGNuPtHQwuphk&brandOwner=null' from origin 'http://localhost:3000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'http://localhost:3000, *', but only one is allowed.

To reproduce, build any web app locally, serve from a web server (like NodeJS) from your localhost, open up the console in the browser, and enter the following:

x = new XMLHttpRequest()
x.open("GET", "https://api.nal.usda.gov/fdc/v1/search?generalSearchInput=a&api_key=<API_KEY>")
x.send()

Despite the API working in production on non-localhost origins, it fails on localhost when the Origin header on the request is set to localhost:<port>. This is extremely significant because it prevents anyone from dev'ing on localhost.

Happy to help with this one if I can if the code is open sourced somewhere!

littlebunch commented 4 years ago

@seanharr11 This should be taken care of. Contact me if you need further...

seanharr11 commented 4 years ago

Hi @littlebunch - this appears to still be an issue, see below for header details (many headers seem to be set twice). Note that this is a CORS XMLHttpRequest made from the browser.

Request Headers

GET /fdc/v1/search?generalSearchInput=s&api_key=oDMbMNfX1gaeV7gaU6qpvpRaWRszGNuPtHQwuphk&brandOwner= HTTP/1.1
Host: api.nal.usda.gov
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
accept: application/json
Origin: http://localhost:3000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: cors
Referer: https://api.nal.usda.gov/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9

Response Headers

HTTP/1.1 200
Server: openresty
Date: Thu, 26 Dec 2019 22:01:01 GMT
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: POST, PUT, GET, OPTIONS, DELETE
Access-Control-Allow-Headers: x-requested-with, Content-Type, Authorization
Access-Control-Max-Age: 3600
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Age: 5
Via: https/1.1 api-umbrella (ApacheTrafficServer [cMsSf ])
X-Cache: MISS
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Content-Encoding: gzip
littlebunch commented 4 years ago

@seanharr11 First, can I ask you to try one more time just to make sure I changed the correct nodes? If the issue remains (and I suspect it will), could you make a XHR call to https://go.littlebunch.com/v1/foods/search?q=broccoli&max=10? In the meanwhile I'll check with people who know more about this stuff than I.

RxDave commented 4 years ago

The issue still remains. I'll try making the XHR call to the URL you posted and let you know.

seanharr11 commented 4 years ago

The request to your GO API came back with the correct headers:

access-control-allow-headers: x-requested-with, Content-TYpe
access-control-allow-methods: POST,GET,OPTIONS
access-control-allow-origin: *
access-control-max-age: 3600
content-length: 1594
content-type: application/json; charset=utf-8
date: Fri, 27 Dec 2019 21:24:48 GMT
server: nginx/1.16.1
status: 200

So it is definitely specific to the server config on the USDA endpoint. Feel free to shoot me an email and we can scheduled a phone call from there if you'd like: seanharr11@gmail.com

RxDave commented 4 years ago

Sorry for the delay in my response. I can also confirm that your API responds with the correct headers (no duplications):

access-control-allow-headers: x-requested-with, Content-TYpe access-control-allow-methods: POST,GET,OPTIONS access-control-allow-origin: * access-control-max-age: 3600 content-length: 1594 content-type: application/json; charset=utf-8 date: Fri, 27 Dec 2019 21:43:42 GMT server: nginx/1.16.1 status: 200

littlebunch commented 4 years ago

Thanks @seanharr11, @RxDave . I'm not sure where the openresty injection is coming from but suspect the api.data.gov proxy (API Umbrella). I haven't found anything in their documentation, though. Let me confirm with them and then we should know where to make a correction. Might not be until the beginning of the week until resolved. I'm surprised this has not come up before.... Thanks for the alert!

littlebunch commented 4 years ago

@seanharr11 @RxDave Ok, I'm trying one last thing. Please try your calls again if and when you have a chance.

seanharr11 commented 4 years ago

Bingo! Thank you for the speedy turnaround. I will wait for @RxDave to confirm on his end as well before closing.

RxDave commented 4 years ago

It works for me too! Thanks so much, this API is going to be great. I hope a lot more apps start integrating the data!

seanharr11 commented 4 years ago

Same here - keep fighting the good fight @littlebunch ... thanks for your help.