Unable to make CORS request in ExtJS 6 - ajax

So, I have my localhost with a page, which sends request to a remote site. I try to do it like so:
Ext.Ajax.cors = true;
Ext.Ajax.request({
url: "http://remoteaddress.com",
method: "GET",
headers: {
"Access-Control-Allow-Origin": "*"
},
cors: true,
useDefaultXhrHeader: false,
success: function (result, request) {
console.log("success!!!");
}
});
So, I followed dozens of threads and set these parameters - cors, useDefaultXhrHeader etc, but to no avail.
However, if I build the same request in postman (request to the same remoteaddress.com), then it's ok.
So, what I'm doing wrong and how can I fix it?

The request with the OPTIONS-method is a preflight request.
From msdna:
A CORS preflight request is a CORS request that checks to see if the
CORS protocol is understood.
It is an OPTIONS request, using three HTTP request headers:
Access-Control-Request-Method, Access-Control-Request-Headers, and the
Origin header.
A preflight request is automatically issued by a browser, when needed.
In normal cases, front-end developers don't need to craft such
requests themselves.
The webserver has to answer it with the headers to allow the browser to do the actual request.
HTTP/1.1 200 OK
Content-Length: 0
Connection: keep-alive
Access-Control-Allow-Origin: localhost
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE
Access-Control-Max-Age: 86400

Here is a quick fix for that
Open terminal and run this code
open -n -a /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --args --user-data-dir="/tmp/chrome_dev_sess_1" --disable-web-security
Then just use that new chrome window for development and once you host your website somewhere it will not cause an issue anymore
*note this is MacOs chrome *

Related

Browser not sending cookies for cross-origin request using Fetch API (Firefox)

On a given domain (https://example.com) I have set cookies using SameSite=None; Secure; HttpOnly
On another site (https://example.org) I am making a fetch request:
fetch('https://example.com/secure/', {method: 'GET', credentials: 'include'})
From what I can see looking in Firefox's network tab there's no pre-flight OPTIONS request being sent. The GET request contains a Host header, Origin header but no Cookies header. The response contains access-control-allow-credentials: true, access-control-allow-origin: https://example.org and vary: origin, true
The response from example.com is returning a 401 due to no cookie being sent.
I can't figure out how to make the browser send cookies (I'm also not certain this is isolated to Firefox).

ajax get request to Office365 REST Api fails CORS?

I'm attempting to make an ajax GET request to the Office365 RESTful API service from my local server, but am running into cross-domain HTTPRequest errors. The following is a sample of my 'get-files-at-root' attempt:
$.ajax({
url: 'https://[sharepoint_site]/_api/v1.0/me/files?access_token='+token,
type: 'get',
dataType: 'json',
success: function(data) {
if (success){
success(data);
}
},
error: error
})
I'm getting the following response from the server:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 403.
I've tried sending the access token as a header parameter:
headers: {'Authorization': 'Bearer '+ token}
but this had the same result.
Any ideas on what I'm doing wrong?
(Background: I'm trying to create my own Office365 'file picker' on the client because I couldn't find an available library for OneDrive Business that supplies this.)
Office 365 Files API and SharePoint REST have just introduced support for CORS.
https://msdn.microsoft.com/en-us/office/office365/howto/create-web-apps-using-CORS-to-access-files-in-Office-365
What you were trying to do is exactly how it works. The service will respond to the OPTIONS pre-flight request with an Access-Control-Allow-Origin header.
The authorization in the request must be an Azure Active Directory issued OAuth2 implicit grant access token.
You have no idea about CORS. Read the specification: http://www.w3.org/TR/cors/
In your case you have to allow null origin, since we are talking about localhost. You have to allow the methods and the headers you send, even the content-type header. You have to allow sending credentials, which you can get in the Authorization header. You have to handle OPTIONS requests with 200 ok.
response.setHeader("Access-Control-Allow-Origin", "*");
response.setCharacterEncoding("UTF-8");
response.setHeader("Access-Control-Allow-Methods", "POST, GET");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
Can you try with setting the Access-Control-Allow-Origin in header as shown below.
headers: { 'Access-Control-Allow-Origin': '*' }

Why is this CORS request failing only in Firefox?

I'm implementing CORS with credentials and a preflight request and I'm a bit mystified why the preflight request consistently fails in Firefox 30 but works in Safari (7.0.2) and Chrome 35. I think this issue is different from "Why does the preflight OPTIONS request of an authenticated CORS request work in Chrome but not Firefox?" because I am not getting a 401, but rather a CORS-specific message from the browser client:
"Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://myurl.dev.com. This can be fixed by moving the resource to the same domain or enabling CORS."
Without showing source code, here's what I'm doing:
On the server:
Headers for OPTIONS response:
Access-Control-Allow-Origin: [[copy origin from the request here]]
Access-Control-Allow-Methods: "POST GET OPTIONS"
Access-Control-Allow-Headers: "X-Requested-With"
Access-Control-Allow-Credentials: "true"
Headers for POST response:
Access-Control-Allow-Origin: [[copy origin from the request here]]
Access-Control-Allow-Credentials: "true"
In the browser client:
jQuery.ajax({
url: requestUrl,
type: 'POST',
data: getData(),
xhrFields: {
withCredentials: true
}
});
Per the spec, this will trigger a OPTIONS preflight request which needs to have the CORS headers in its response. I've read through the W3C spec several times and I can't identify what I'm doing wrong, if anything, in that preflight response.
QUESTION: "Why is this CORS request failing only in Firefox?"
ANSWER: While unrelated to the OP's specific case, it may help you to know that Firefox does not trust CA's (certificate authorities) in the Windows Certificate Store by default, and this can result in failing CORS requests in Firefox (as was alluded to by Svish in the question comments).
To allow Firefox to trust CA's in the Windows Certificate Store:
In Firefox, type about:config in the address bar
If prompted, accept any warnings
Right-click to create a new boolean value, and enter security.enterprise_roots.enabled as the Name
Set the value to true
Then re-test the failing request
Answer source: https://support.umbrella.com/hc/en-us/articles/115000669728-Configuring-Firefox-to-use-the-Windows-Certificate-Store
Note that Firefox is the only browser that is compliant here. If parsing of Access-Control-Allow-Methods fails per https://fetch.spec.whatwg.org/#cors-preflight-fetch a network error needs to be returned. And per the ABNF for the header value it is most definitely a comma-separated value.
Disabling HTTPS-Only Mode in Firefox solved the issue for me.
I was trying to access a remote resource using HTTP from http://localhost.
Since Firefox 87 (released in March 2021), it's possible to set the below preference in about:config, namely the Firefox Configuration Editor:
network.cors_preflight.allow_client_cert: true
From Firefox for Enterprise 87 - Release notes:
Corporations that use TLS client certificates can flip the network.cors_preflight.allow_client_cert preference to get Google Chrome-compatible handling of the CORS protocol. In particular, contrary to the Fetch Standard, this will transmit TLS client certificates along with a CORS preflight. See bug 1511151 for more information.
References:
https://support.mozilla.org/en-US/kb/firefox-enterprise-87-release-notes
https://bugzilla.mozilla.org/show_bug.cgi?id=1511151
I have noticed that when you a send CORS(Cross Origin Resource Sharing) request with cookies set, Firefox doesn't send the required response headers.
Solution:
Below solution adds headers only for OPTIONS requests and accepts requests only from example.com. You can change the implementation for other request methods and expected hosts.
JS CODE
var xmlhttp = new XMLHttpRequest();
xmlhttp.withCredentials = true;
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (xmlhttp.status == 200) {
success_callback(xmlhttp.responseText);
} else {
error_callback(xmlhttp.statusText);
}
}
};
xmlhttp.open("DELETE", url);
xmlhttp.send(null);
When you send a DELETE request, the browser send a pre-flight request for OPTIONS, which expects Access-Control-Allow-Methods in the response headers. Based on this header value the actual DELETE request is sent. In Firefox, when you send a DELETE request the pre-flight request's response headers do not have expected headers, therefore it fails to send the actual DELETE request.
To overcome this problem use the below NGINX server config.
NGINX CODE
#handle CORS requests by adding required headers
if ($http_origin ~* .example.com) {
set $cors "CORS-${request_method}";
}
if ($cors = "CORS-OPTIONS") {
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Content-Type';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE';
add_header 'Access-Control-Allow-Origin' $http_origin;
}
Good read on CORS: https://www.html5rocks.com/en/tutorials/cors/

Chrome: GET request cancelled for CORS HTTPS request

I am trying to make an AJAX request to download a JSON file from S3 using the following code:
$.ajax({
'type':'GET',
'url':this.baseUrl + publicationId + "/document.json",
'crossDomain': true,
'dataType':'json',
'success':function(data) {
console.log('got document.json');
}
});
This works fine in Firefox, and it works if the baseUrl is http ://<s3-url>, but if it is https://, then Chrome cancels the request with the error:
XMLHttpRequest cannot load
https ://s3.amazonaws.com/<bucket-name>/<pub-id>/document.json. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'https ://localhost.office.lucidpress.com' is
therefore not allowed access.
Making the same request with CURL does have the following header: "Access-Control-Allow-Origin: *".
Why doesn't this work for Chrome, and is there any workaround?
Note: I put spaces in the URLs to prevent them from becoming links.
Chrome will send a pre-flight OPTIONS request to see if the GET can be performed. What headers do you receive if you curl -X OPTIONS -i https://s3.amazonaws.com/<bucket-name>/<pub-id>/document.json? You most likely need to add Access-Control-Allow-Headers to your server response to also allow any extra headers Chrome may be sending on the OPTIONS request, i.e. Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Alternatively, as this is a https request, your answer may be Why Chrome cancel CORS OPTION request

Why is the browser not setting cookies after an AJAX request returns?

I am making an ajax request using $.ajax. The response has the Set-Cookie header set (I've verified this in the Chrome dev tools). However, the browser does not set the cookie after receiving the response! When I navigate to another page within my domain, the cookie is not sent. (Note: I'm not doing any cross-domain ajax requests; the request is in the same domain as the document.)
What am I missing?
EDIT: Here is the code for my ajax request:
$.post('/user/login', JSON.stringify(data));
Here is the request, as shown by the Chrome dev tools:
Request URL:https://192.168.1.154:3000/user/login
Request Method:POST
Status Code:200 OK
Request Headers:
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:35
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
DNT:1
Host:192.168.1.154:3000
Origin:https://192.168.1.154:3000
Referer:https://192.168.1.154:3000/
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36
X-Requested-With:XMLHttpRequest
Form Data:
{"UserId":"blah","Password":"blah"}:
Response:
Response Headers:
Content-Length:15
Content-Type:application/json; charset=UTF-8
Date:Sun, 16 Mar 2014 03:25:24 GMT
Set-Cookie:SessionId=MTM5NDk0MDMyNHxEdi1CQkFFQ180SUFBUkFCRUFBQVRfLUNBQUVHYzNSeWFXNW5EQXNBQ1ZObGMzTnBiMjVKWkFaemRISnBibWNNTGdBc1ZFcDNlU3RKVFdKSGIzQlNXRkkwVjJGNFJ6TlRVSHA0U0ZJd01XRktjMDF1Y1c1b2FGWXJORzV4V1QwPXwWf1tz-2Fy_Y4I6fypCzkMJyYxhgM3LjVHGAlKyrilRg==; HttpOnly
OK, so I finally figured out the problem. It turns out that setting the Path option is important when sending cookies in an AJAX request. If you set Path=/, e.g.:
Set-Cookie:SessionId=foo; Path=/; HttpOnly
...then the browser will set the cookie when you navigate to a different page. Without setting Path, the browser uses the "default" path. Apparently, the default path for a cookie set by an AJAX request is different from the default path used when you navigate to a page directly. I'm using Go/Martini, so on the server-side I do this:
session.Options(session.Options{HttpOnly: true, Path:"/"})
I'd guess that Python/Ruby/etc. have a similar mechanism for setting Path.
See also: cookies problem in PHP and AJAX
#atomkirk's answer didn't apply to me because
I don't use the fetch API
I was making cross-site requests (i.e. CORS)
NOTE: If your server is using Access-Control-Allow-Origins:* (aka "all origins"/"wildcard origins"), you may not be able to send credentials (see below).
As for the fetch API; CORS requests will need {credentials:'include'} for both sending & receiving cookies
For CORS requests, use the "include" value to allow sending
credentials to other domains:
fetch('https://example.com:1234/users', {
credentials: 'include'
})
... To opt into accepting cookies from the server, you must use the credentials option.
{credentials:'include'} just sets xhr.withCredentials=true
Check fetch code
if (request.credentials === 'include') {
xhr.withCredentials = true
}
So plain Javascript/XHR.withCredentials is the important part.
If you're using jQuery, you can set withCredentials (remember to use crossDomain: true) using $.ajaxSetup(...)
$.ajaxSetup({
crossDomain: true,
xhrFields: {
withCredentials: true
}
});
If you're using AngularJS, the $http service config arg accepts a withCredentials property:
$http({
withCredentials: true
});
If you're using Angular (Angular IO), the common.http.HttpRequest service options arg accepts a withCredentials property:
this.http.post<Hero>(this.heroesUrl, hero, {
withCredentials: true
});
As for the request, when xhr.withCredentials=true; the Cookie header is sent
Before I changed xhr.withCredentials=true
I could see Set-Cookie name & value in the response, but Chrome's "Application" tab in the Developer Tools showed me the name and an empty value
Subsequent requests did not send a Cookie request header.
After the change xhr.withCredentials=true
I could see the cookie's name and the cookie's value in the Chrome's "Application" tab (a value consistent with the Set-Cookie header).
Subsequent requests did send a Cookie request header with the same value, so my server treated me as "authenticated"
As for the response: the server may need certain Access-Control... headers
For example, I configured my server to return these headers:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:https://{your-origin}:{your-port}
EDIT: this approach won't work if you allow all origins/wildcard origins, as described here (thanks to #ChandanBhattad) :
The CORS request was attempted with the credentials flag set, but the server is configured using the wildcard ("*") as the value of Access-Control-Allow-Origin, which doesn't allow the use of credentials.
Until I made this server-side change to the response headers, Chrome logged errors in the console like
Failed to load https://{saml-domain}/saml-authn: Redirect from https://{saml-domain}/saml-redirect has been blocked by CORS policy:
The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. Origin https://{your-domain} is therefore not allowed access.
The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
After making this Access-* header change, Chrome did not log errors; the browser let me check the authenticated responses for all subsequent requests.
If you're using the new fetch API, you can try including credentials:
fetch('/users', {
credentials: 'same-origin'
})
That's what fixed it for me.
In particular, using the polyfill: https://github.com/github/fetch#sending-cookies
This may help somebody randomly falling across this question.
I found forcing a URL with https:// rather than http:// even though the server hasn't got a certificate and Chrome complains will fix this issue.
In my case, the cookie size exceeded 4096 bytes (Google Chrome). I had a dynamic cookie payload that would increase in size.
Browsers will ignore the set-cookie response header if the cookie exceeds the browsers limit, and it will not set the cookie.
See here for cookie size limits per browser.
I know this isn't the solution, but this was my issue, and I hope it helps someone :)

Resources