CORS error with react native app run with expo web [duplicate] - reactjs

I created an API endpoint using Google Cloud Functions and am trying to call it from a JS fetch function.
I am running into errors that I am pretty sure are related to either CORS or the output format, but I'm not really sure what is going on. A few other SO questions are similar, and helped me realize I needed to remove the mode: "no-cors". Most mention enabling CORS on the BE, so I added response.headers.set('Access-Control-Allow-Origin', '*') - which I learned of in this article - to ensure CORS would be enabled... But I still get the "Failed to fetch" error.
The Full Errors (reproducible in the live demo linked below) are:
Uncaught Error: Cannot add node 1 because a node with that id is
already in the Store. (This one is probably unrelated?)
Access to fetch at
'https://us-central1-stargazr-ncc-2893.cloudfunctions.net/nearest_csc?lat=37.75&lon=-122.5'
from origin 'https://o2gxx.csb.app' has been blocked by CORS policy:
Request header field access-control-allow-origin is not allowed by
Access-Control-Allow-Headers in preflight response.
GET
https://us-central1-stargazr-ncc-2893.cloudfunctions.net/nearest_csc?lat=37.75&lon=-122.5 net::ERR_FAILED
Uncaught (in promise) TypeError: Failed to fetch
See Code Snippets below, please note where I used <---- *** Message *** to denote parts of the code that have recently changed, giving me one of those two errors.
Front End Code:
function getCSC() {
let lat = 37.75;
let lng = -122.5;
fetch(
`https://us-central1-stargazr-ncc-2893.cloudfunctions.net/nearest_csc?lat=${lat}&lon=${lng}`,
{
method: "GET",
// mode: "no-cors", <---- **Uncommenting this predictably gets rid of CORS error but returns a Opaque object which seems to have no data**
headers: {
// Accept: "application/json", <---- **Originally BE returned stringified json. Not sure if I should be returning it as something else or if this is still needed**
Origin: "https://lget3.csb.app",
"Access-Control-Allow-Origin": "*"
}
}
)
.then(response => {
console.log(response);
console.log(response.json());
});
}
Back End Code:
import json
import math
import os
import flask
def nearest_csc(request):
"""
args: request object w/ args for lat/lon
returns: String, either with json representation of nearest site information or an error message
"""
lat = request.args.get('lat', type = float)
lon = request.args.get('lon', type = float)
# Get list of all csc site locations
with open(file_path, 'r') as f:
data = json.load(f)
nearby_csc = []
# Removed from snippet for clarity:
# populate nearby_csc (list) with sites (dictionaries) as elems
# Determine which site is the closest, assigned to var 'closest_site'
# Grab site url and return site data if within 100 km
if dist_km < 100:
closest_site['dist_km'] = dist_km
// return json.dumps(closest_site) <--- **Original return statement. Added 4 lines below in an attempt to get CORS set up, but did not seem to work**
response = flask.jsonify(closest_site)
response.headers.set('Access-Control-Allow-Origin', '*')
response.headers.set('Access-Control-Allow-Methods', 'GET, POST')
return response
return "No sites found within 100 km"
Fuller context for code snippets above:
Here is a Code Sandbox Demo of the above.
Here is the full BE code on GitHub, minus the most recent attempt at adding CORS.
The API endpoint.
I'm also wondering if it's possible that CodeSandbox does CORS in a weird way, but have had the same issue running it on localhost:3000, and of course in prod would have this on my own personal domain.
The Error would appear to be CORS-related ( 'https://o2gxx.csb.app' has been blocked by CORS policy: Request header field access-control-allow-origin is not allowed by Access-Control-Allow-Headers in preflight response.) but I thought adding response.headers.set('Access-Control-Allow-Origin', '*') would solve that. Do I need to change something else on the BE? On the FE?
TLDR;
I am getting the Errors "Failed to fetch" and "field access-control-allow-origin is not allowed by Access-Control-Allow-Headers" even after attempts to enable CORS on backend and add headers to FE. See the links above for live demo of code.

Drop the part of your frontend code that adds a Access-Control-Allow-Origin header.
Never add Access-Control-Allow-Origin as a request header in your frontend code.
The only effect that’ll ever have is a negative one: it’ll cause browsers to do CORS preflight OPTIONS requests even in cases when the actual (GET, POST, etc.) request from your frontend code would otherwise not trigger a preflight. And then the preflight will fail with this message:
Request header field Access-Control-Allow-Origin is not allowed by Access-Control-Allow-Headers in preflight response
…that is, it’ll fail with that unless the server the request is being made to has been configured to send an Access-Control-Allow-Headers: Access-Control-Allow-Origin response header.
But you never want Access-Control-Allow-Origin in the Access-Control-Allow-Headers response-header value. If that ends up making things work, you’re actually just fixing the wrong problem. Because the real fix is: never set Access-Control-Allow-Origin as a request header.
Intuitively, it may seem logical to look at it as “I’ve set Access-Control-Allow-Origin both in the request and in the response, so that should be better than just having it in the response” — but it’s actually worse than only setting it in the response (for the reasons described above).
So the bottom line: Access-Control-Allow-Origin is solely a response header, not a request header. You only ever want to set it in server-side response code, not frontend JavaScript code.
The code in the question was also trying to add an Origin header. You also never want to try to set that header in your frontend JavaScript code.
Unlike the case with the Access-Control-Allow-Origin header, Origin is actually a request header — but it’s a special header that’s controlled completely by browsers, and browsers won’t ever allow your frontend JavaScript code to set it. So don’t ever try to.

Related

reactJS app with a fetch to an API fails to load with No 'Access-Control-Allow-Origin' header is present on the requested resource

I have the following code which worked 6 days ago:
function showProduct(barcode) {
let url = "https://api.barcodelookup.com/v2/products?barcode=" + barcode + "&key=mj1pm32ylcctxj1byaiaxxxxxxxxxx";
const options = { method: 'GET' };
fetch(url, options)
.then(function(response) {
return response.json();
})
.then(function(myJson) {
setTimeout(function(){
if (myJson == undefined)
{
console.log("fetch failed")
}
else
{
//inspect the data that the WebAPI returned
console.log("myJson: ", myJson);
console.log(myJson.products[0].barcode_formats);
Quagga.stop();
}
}, 3000);
});
}
and the value being passed into the function is 5000159459228. When I executed this code last week, I was receiving a response back from the API and I was able to pick up the individual fields being returned.
Today, I started debugging a different feature of my app and now I receive this error when executing the above listed code:
Failed to load https://api.barcodelookup.com/v2/products?barcode=5000159459228&key=mj1pm32ylcctxj1byaiaxxxxxxxxxx: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
followed by this error:
Uncaught (in promise) TypeError: Failed to fetch
and then this:
newscan:91 Cross-Origin Read Blocking (CORB) blocked cross-origin response https://api.barcodelookup.com/v2/products?barcode=5000159459228&key=mj1pm32ylcctxj1byaiaxxxxxxxxxx with MIME type application/json. See https://www.chromestatus.com/feature/5629709824032768 for more details.
If I manually paste the string that I build into the url variable into a browser, I do get a valid response back.
Any suggestions?
Jonathan what you have there is a cors problem. A quick way to solve that if you are using express in your backend is just add CORS module with npm i --save cors and then use it as a middleware:
const cors = require('cors');
app.use(cors());
You can always add the headers yourself. Take a deepr look at Enable CORS.org
Your question was also answered here: [No 'Access-Control-Allow-Origin' header is present on the requested resource—when trying to get data from a REST API

Laravel 5.2 and angularJS token mismatch

I am developing a webapp with static files on one server and api on another. The front end is developed using angular and backend using laravel.
For CSRF-TOKEN fetching during the first load, within angular run block I have this code
if(!$cookies.get('XSRF-TOKEN')){
$http.get(API+'/csrf_token').success(function(d){
$cookies.put('XSRF-TOKEN',d.XSRF_TOKEN);
//$cookies.put('laravel-session',d.LARAVEL_ID);
//$http.defaults.headers.common.X-CSRF-TOKEN = 'Basic YmVlcDpib29w';
//$http.defaults.headers.post['X-CSRF-TOKEN']=$cookies.get('XSRF-TOKEN');
$http.defaults.headers.post['X-CSRF-TOKEN']=d.XSRF_TOKEN;
});
The other way I have tried to get the same was using this way.
Also set $httpProvider.defaults.withCredentials = true; so that cookies be sent along with requests.
The route /csrf_token setup as
Route::get("/csrf_token", function(){
//return \Response::json("asd",200)->withCookie(cookie("XSRF-TOKEN",csrf_token()));
return csrf_token(); //\Crypt::encrypt(csrf_token())
});
All the ajax POST requests throw TokenMismatchException in VerifyCsrfToken.php line 67:.
Next I have sent the csrf_token parameter as _token attached with the post parameters, still the same problem.
Tried all the above, returning encrypted token from /csrf_token, but still same problem.
Repeated all the steps clearing the config:cache and composer dumpautoload in api server, but still same problem.
Reviewed config file ,some values -
'driver' => env('SESSION_DRIVER', 'file'),
'encrypt' => false,
'files' => storage_path('framework/sessions'),
'secure' => false,
(These values seem to be okay)
Next reviewed Virtual config file for CORS configuration (inside directory tag)
Header set Access-Control-Allow-Origin "www.mydomain.com" #real domain not posted
Header set Access-Control-Allow-Credentials 'true'
Header always set Access-Control-Max-Age "2000"
Header set Access-Control-Allow-Headers 'X-CSRF-TOKEN'
Header always set Access-Control-Allow-Headers "X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
Options Indexes FollowSymLinks Includes ExecCGI
AllowOverride All
Require local
Wasted hours googling.(frustrated). Need help.
NB: I couldn't find any more tutorial/answers similar to token mismatch problem netiher on stackoverflow nor on any other website that I havn't tried. Thanks.

Mitigating reflected XSS in node/express requests for static assets

I've run a pen test tool (Burp) against my node(express)/angular application and it identified a reflected XSS vulnerability specifically when attempting a GET request for static assets (noticeably vulnerabilities were not found for any of the requests being made when a user interacts with the application).
The issue detail is:
The name of an arbitrarily supplied URL parameter is copied into a
JavaScript expression which is not encapsulated in any quotation
marks. The payload 41b68(a)184a9=1 was submitted in the name of an
arbitrarily supplied URL parameter. This input was echoed unmodified
in the application's response.
This behavior demonstrates that it is possible to inject JavaScript
commands into the returned document. An attempt was made to identify a
full proof-of-concept attack for injecting arbitrary JavaScript but
this was not successful. You should manually examine the application's
behavior and attempt to identify any unusual input validation or other
obstacles that may be in place.
The vulnerability was tested by passing an arbitrary url parameter to the request like so:
GET /images/?41b68(a)184a9=1
The response was:
HTTP/1.1 404 Not Found
X-Content-Security-Policy: connect-src 'self'; default-src 'self'; font-src 'self'; frame-src; img-src 'self' *.google-analytics.com; media-src; object-src; script-src 'self' 'unsafe-eval' *.google-analytics.com; style-src 'self' 'unsafe-inline'
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
Strict-Transport-Security: max-age=10886400; includeSubDomains; preload
X-Download-Options: noopen
X-Content-Type-Options: nosniff
Content-Type: text/html; charset=utf-8
Content-Length: 52
Date: Wed, 08 Oct 2015 10:46:43 GMT
Connection: close
Cannot GET /images/?41b68(a)184a9=1
You can see that I have CSP in place (using Helmet to implement) and other protections against exploits. The app is served over https, but no user auth is required. CSP restricts request to the app's domain only plus google analytics.
The pen test report advises validating input (I am, but surely that would make requests including data sent by a user unsafe if I wasn't?), and encoding html which angular does by default.
I'm really struggling to find a solution to preventing or mitigating this for those requests for static assets:
Should I whitelist all requests for my application under csp?
Can I even do this, or will it only whitelist domains?
Can/should all responses from node/express to requests for static assets be encoded in some way?
The report states that "The name of an arbitrarily supplied URL parameter is copied into a JavaScript expression which is not encapsulated in any quotation marks". Could this expression be somewhere in the express code that handles returning static assets?
Or that GET request param can somehow be evaluated in my application code?
Update
Having done some investigation into this it seems that at least part of the mitigation is to escape data in url param values and sanitize the input in the url.
Escaping of the url is already in place so:
curl 'http://mydomain/images/?<script>alert('hello')</script>'
returns
Cannot GET /images/?<script>alert(hello)</script>
I've also put express-sanitized in place on top of this.
However, if I curl the original test the request param is still reflected back.
curl 'http://mydomain/images/?41b68(a)184a9=1'
Cannot GET /images/?41b68(a)184a9=1
Which you would expect because html is not being inserted into the url.
The responses to GET requests for static assets are all handled by app.use(express.static('static-dir')) so the query is passed into this. express.static is based on serve-static which depends on parseurl.
The cause of the issue is that for invalid GET requests express will return something like:
Cannot GET /pathname/?yourQueryString
Which in many cases is a valid response, even for serving static assets. However, in my case and I'm sure for others the only valid requests for static assets will be something like:
GET /pathname/your-file.jpg
I have a custom 404 handler that returns a data object:
var data = {
status: 404,
message: 'Not Found',
description: description,
url: req.url
};
This is only handled for invalid template requests in app.js with:
app.use('/template-path/*', function(req, res, next) {
custom404.send404(req, res);
});
I've now added explicit handlers for requests to static folders:
app.use('/static-path/*', function(req, res, next) {
custom404.send404(req, res);
});
Optionally I could also strip out request query params before the 404 is returned:
var data = {
status: 404,
message: 'Not Found',
description: description,
url: url.parse(req.url).pathname // needs a var url = require('url')
};

angularJS $http.Post not working: Failed to load resource: Request header field 0 is not allowed by Access-Control-Allow-Headers

I'm using $http to post some data to my data base.
Here is the documentation of the database.
I use it on my terminal and it works.
Here's the error message I got from Safari's console:
1)Failed to load resource: Request header field 0 is not allowed by Access-Control-Allow-Headers. (seems to be sensed by the database)
2)XMLHttpRequest cannot load https://beta-api.mongohq.com/mongo/MyDId/myDatabse/collections/myCollection/documents. Request header field 0 is not allowed by Access-Control-Allow-Headers.
Here's my code:
factory.sendUrlTag = function(data){
d = '{"document" : {"url_URL":"53738eef9256a31f4fdf6bf8","tag_Tag":"537375fc9256a31f4fdf6bf3"} }'
return $http({
url: 'https://beta-api.mongohq.com/mongo/MyDId/myDatabse/collections/myCollection/documents',
method: "POST",
data: d,
headers: [
{'Access-Control-Allow-Origin':'*'},
{'Access-Control-Allow-Headers':'Origin, X-Requested-With, Content-Type, Accept'},
{'Content-Type': 'application/json'},
{'Authorization' : 'api-key MyKey'}
]
})
}
return factory;
};
I didn't have " {'Access-Control-Allow-Origin':'*'},
{'Access-Control-Allow-Headers':'Origin, X-Requested-With, Content-Type, Accept'}," before, but I did some research after I got the error and added these. But it's still not working.
I do $http.get() in my app to the same database and it works.
This thing is driving me nuts....
Please help!
Thank you all! :)
Access-Control-Allow-Origin and friends are response headers, not request headers. It wouldn't make sense if Bob was responsible for granting Bob permission to Alice's system.
The server (https://beta-api.mongohq.com/mongo/MyDId/myDatabse/collections/myCollection/documents) has to send them, not the client.
Since you are making a cross-origin POST request, the server also needs to be able to respond to a pre-flight OPTIONS request.
I found some way maybe able to get around the issue:
Use this and here to get around the cross origin origin issue.
And this to get around the localhost
It may work.
Another relative post.

NetworkError: 405 Method Not Allowed AngularJS REST

In AngularJS, I had the following function, which worked fine:
$http.get( "fruits.json" ).success( $scope.handleLoaded );
Now I would like to change this from a file to a url (that returns json using some sweet Laravel 4):
$http.get( "http://localhost/fruitapp/fruits").success( $scope.handleLoaded );
The error I get is:
"NetworkError: 405 Method Not Allowed - http://localhost/fruitapp/fruits"
What's the problem? Is it because fruit.json was "local" and localhost is not?
From w3:
10.4.6 405 Method Not Allowed
The method specified in the Request-Line is not allowed for the resource
identified by the Request-URI. The response MUST include an Allow header
containing a list of valid methods for the requested resource.
It means the for the URL: http://localhost/fruitapp/fruits The server is responding that the GET method isn't allowed. Is it a POST or PUT?
The angular js version you are using would be <= 1.2.9.
If Yes, try this.
return $http({
url: 'http://localhost/fruitapp/fruits',
method: "GET",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
I had a similar issue with my SpringBoot project, I was getting the same error in the browser console but I saw a different error message when I looked at the back-end log, It was throwing this error: "org.springframework.web.HttpRequestMethodNotSupportedException, message=Request method 'DELETE' not supported " It turned out that I was missing the {id} parameter in the back-end controller:
** Wrong code :**
#RequestMapping(value="books",method=RequestMethod.DELETE)
public Book delete(#PathVariable long id){
Book deletedBook = bookRepository.findOne(id);
bookRepository.delete(id);
return deletedBook;
}
** Correct code :**
#RequestMapping(value="books/{id}",method=RequestMethod.DELETE)
public Book delete(#PathVariable long id){
Book deletedBook = bookRepository.findOne(id);
bookRepository.delete(id);
return deletedBook;
}
For me, it was the server not being configured for CORS.
Here is how I did it on Azure: CORS enabling on Azure
I hope something similar works with your server, too.
I also found a proposal how to configure CORS on the web.config, but no guarantee: configure CORS in the web.config. In general, there is a preflight request to your server, and if you did a cross-origin request (that is from another url than your server has), you need to allow all origins on your server (Access-Control-Allow-Origin *).

Resources