CORS error in AngularJS - javascript

When I am using Fiddler or any browser side HTTP client extension like Advanced Rest Client, I can get data from a API easily.
But when I try to use the same API from Angular JS, CORS issue appear immediately. I have tried with following lines to solve the problem in AngularJS, But unfortunately it did not work.
appd.config(function ($httpProvider) {
// $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
// $httpProvider.defaults.headers.post['Accept'] = '*/*'
$httpProvider.defaults.useXDomain = true;
$httpProvider.defaults.withCredentials = true;
delete $httpProvider.defaults.headers.common["X-Requested-With"];
$httpProvider.defaults.headers.common["Accept"] = "*/*";
$httpProvider.defaults.headers.common["Content-Type"] = "application/x-www-form-urlencoded";
$httpProvider.defaults.headers.common['Authorization'] = 'Basic encodedpassword=';
});
I get following error in mozilla:
Cross-Origin Request Blocked:
The Same Origin Policy disallows reading the remote resource at http://host/training_webapi. This can be fixed by moving the resource to the same domain or enabling CORS.
And following in Chrome:
XMLHttpRequest cannot load http://host/training_webapi The request was redirected to 'http:host/training_webapi/', which is disallowed for cross-origin requests that require preflight.

The service you are requesting is not allowing CORS (no Access-Control are sent as part of the response).
You would need to include the header Access-Control-Allow-Origin: * as part of the response (which it does not).
See this : http://www.html5rocks.com/en/tutorials/cors/

You might be able to use $http.jsonp.
var url = "http://host/training_webapi?callback=JSON_CALLBACK";
$http.jsonp(url)
.success(function(data){
console.log(data.found);
});
Working JSFiddle
Another option (since you don't own the server), could be to proxy the request on your server and access that URI using angular.
One more point, in your code the content header is set to form:
$httpProvider.defaults.headers.common["Content-Type"] = "application/x-www-form-urlencoded";
Your request should be expecting
content-type: application/json

Related

CORS on api of Codechef (using angularjs)

The following url gives the ranking of any contest in JSON format
https://www.codechef.com/api/rankings/OCT17
Just replace OCT17 with any contest code
I thought of making a web app which will fetch this api and display a custom leaderboard.I tried using the angularjs but it is CORS error
This is code
var app = angular.module('Ranklist', []);
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
console.log("cross origin allowed");
}
]);
app.controller('rank',function($scope,$http){
var uri = 'https://www.codechef.com/api/rankings/COPH2017?sortBy=rank&order=asc&page=1&itemsPerPage=25';
$scope.test = "test data";
console.log("love can hear")
$http.get(uri)
.then(function(response){
$scope.data = response.data;
});
});
Console is showing these 2 errors in chrome
Failed to load https://www.codechef.com/api/rankings/COPH2017?sortBy=rank&order=asc&page=1&itemsPerPage=25: The 'Access-Control-Allow-Origin' header has a value 'https://developers.codechef.com that is not equal to the supplied origin. Origin 'http://127.0.0.1:58502' is therefore not allowed access.```
and
angular.js:14525 Possibly unhandled rejection: {"data":null,"status":-1,"config":{"method":"GET","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","url":"https://www.codechef.com/api/rankings/COPH2017?sortBy=rank&order=asc&page=1&itemsPerPage=25","headers":{"Accept":"application/json, text/plain, */*"}},"statusText":""}
There is no error on IE while there is on chrome
Can this be fixed or it is just a server side problem(or their preference)
I also tried $http.jsonp() function.
You cannot make a cross domain request (CORS) on the client browser.
This API only allows requests from https://developers.codechef.com
Given that your request is not coming from that domain you are being denied access.
CORS is only enforced by the browser. Therefore, if you have your own backend server and make a request to that server and your server requests from their server (known as proxying the request) you will be fine since you will avoid the CORS problem.

Cannot POST data cross domain in Angular app

EDIT:
Problem is resolved. My front end code is fine, it's error of back end guys.
I have problem when POST data cross domain. I don't know why, just 3 hours ago it worked fine. At that time I just made some changes in CSS and HTML, I was not touch to any JS file. I also asked the Back end team (They're using Ruby on Rails) and they told me that they still working on localhost.
This error appear every time I try to POST to server when using both Firefox and Chrome:
XMLHttpRequest cannot load https://time-traveler-back.herokuapp.com/api/sessions/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9000' is therefore not allowed access. The response had HTTP status code 503.
For Chrome, I already installed CORS app. But if I turned it on, another error appear:
XMLHttpRequest cannot load https://time-traveler-back.herokuapp.com/api/sessions/login. A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. Origin 'http://localhost:9000' is therefore not allowed access.
Here is my app config:
// Config for POST data cross domain
app.config(['$routeProvider', '$httpProvider', function($routeProvider, $httpProvider) {
$httpProvider.defaults.useXDomain = true;
$httpProvider.defaults.withCredentials = true;
delete $httpProvider.defaults.headers.common["X-Requested-With"];
$httpProvider.defaults.headers.common["Accept"] = "application/json";
$httpProvider.defaults.headers.common["Content-Type"] = "application/json";
}]);
This is how I POST data:
var apiUrl = 'https://time-traveler-back.herokuapp.com/api/';
$http({
method: 'POST',
url: apiUrl + 'sessions/login',
data: $.param(formData), // pass in data as strings
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
} // set the headers so angular passing info as form data (not request payload)
})
.then(function successCallback(response) {
// my stuffs
}, function errorCallback(response) {
// my stuffs
});
Please help me. Thanks.
Credentials and CORS
One thing to note when using withCredentials: true in your app and
configuring the server for CORS is that you may not have your
Access-Control-Allow-Origin header set to '*'. It must be configured
to a few select origins. If you absolutely must have this set to *,
then I suggest doing something beyond cookie based authentication,
such as token-based authentication.
See AngularJS Authentication and CORS
Looks like a standard CORS error.
You already fixed, but in case of doubt, I'll give some recommendations:
Rack-CORS
If using rails as the backend, you should definitely check out the rack-cors gem. This basically sets up all the CORS policies for your server through the middleware in the most simple way possible:
#config/application.rb
...
config.middleware.insert_before 0, "Rack::Cors" do
allow do
origins '*'
resource '*', headers: :any, methods: [:get, :post, :options]
end
end
This allows you to permit particular domains "origins" & methods to your app.
--
You must also remember that to prevent cross domain XML requests, "CORS" (Cross Origin Resource Sharing) was instituted to apply a "lock" on which resources / urls are accessible by JS requests.
As a rule of thumb, if you're ever using JS to automagically update the front-end with an XML request of a separate domain (not just Ajax), you'll need to permit the domain in your server's CORS policy.
There are a number of ways to do this; simplest with rails is to use the rack-CORS gem (as above).

CORs does not get enabled when using XMLHttpRequest?

I have spent hours trying to access a resource from a different domain.
http://www.nczonline.net/blog/2010/05/25/cross-domain-ajax-with-cross-origin-resource-sharing/ which is referenced in other SO posts states that by simply using XMLHttpRequest in a browser that supports CORS, CORS policy should be enabled. However I am still getting
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://www.nczonline.net/. This can be fixed by moving the resource to the same domain or enabling CORS.
When using it in Firefox 34 which according to http://caniuse.com/#feat=cors should be sufficient.
I am trying a simple example from http://www.nczonline.net/blog/2010/05/25/cross-domain-ajax-with-cross-origin-resource-sharing/
<script type="text/javascript">
function log(msg){
var output = $('#output');
output.text(output.text() + " | " + msg);
console.log(msg);
}
function createCORSRequest(method, url){
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr){
xhr.open(method, url, true);
log("'withCredentials' exist in xhr");
} else if (typeof XDomainRequest != "undefined"){
xhr = new XDomainRequest();
xhr.open(method, url);
log("XDomainRequest is being used");
} else {
xhr = null;
log("xhr is null");
}
return xhr;
}
function main(){
log("Attempting to make CORS request");
var request = createCORSRequest("get", "https://www.nczonline.net/");
if (request){
request.onload = function(){
log("LOADED!");
};
request.send();
}
}
$(window).load(function(){
main();
});
</script>
And I am getting the following output:
Attempting to make CORS request
'withCredentials' exist in xhr
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://www.nczonline.net/. This can be fixed by moving the resource to the same domain or enabling CORS.
Trying it on fiddle https://jsfiddle.net/zf8ydb9v/ gives same results. Is there another lever somewhere that needs to switched on to be able to use CORS bBesides using XMLHttpRequest?
The same origin policy (which prevents making of CORS requests) is there for your security, not the security of the server: it prevents malicious scripts to access your data on other servers using your cookies.
So, if you want you can still disable it at your own risk, on your browser.
In Chrome/Chromium, if you want to disable the same origin policy you can start it with the --disable-web-security option:
chromium-browser --disable-web-security
Anyway, if you want it to work for your users, they will not able to make CORS requests if they have not disabled this security check in their browsers (which is discouraged if not for testing).
As noted in other answers, some servers can purposely allow this kind of requests if they believe this can be useful and not harmful for their users, and they can do this with the Access-control headers.
Moreover, if you still want to find a way to provide this kind of functionality to the users, you might make a Chrome extension, which is not bound to the same origin policy.
A common solution to this is to make the cross origin request server side, returning the result to your application. You should be careful coding this: passing the url to fetch to the server will easily cause security concerns for your server side software. But if you have to fetch the same url every time, you could hard code it server side, in PHP would look like something like this:
<?php
echo file_get_contents("http://your_cross_request/");
?>
then making an ajax request to this page (which will be from the same origin) will return the content of the remote url.
CORS headers are found in the response sent by the server to your request. If the requested page isn't sending the header, it doesn't matter what you did with the request in a stock browser, you'll get a security error
The relevant CORS headers look like this, the last being the most important one
Access-Control-Allow-Credentials: false
Access-Control-Allow-Methods: GET
Access-Control-Allow-Origin: *
I tried opening "nczonline.net" and when I looked at the response headers I did not see any of these, so the server is not configured to permit being loaded in this way
If you are an administrator of that website, you may want to consider adding the required headers to your responses, perhaps being specific about permitted origins rather than using the wildcard
If you're simply trying to demo your code and want to try it with a third party, load a page which does send these headers e.g. developer.mozilla.org

ADAL - JavaScript used in Angular JS in SPA app , to call third party APIs exposed through APIGEE giving CORS error

I have created a SPA and used Azure AD for User store and ADAL-JavaScript library as mentioned on a http://www.cloudidentity.com/blog/2014/10/28/adal-javascript-and-angularjs-deep-dive/ to integrate with my angular js code. It did authentication flow successfully, but when I was calling the third party API exposed using APIGEE, I was getting following error messages:
Failed to load resource: the server responded with a status of 502 (Bad Gateway)
XMLHttpRequest cannot load http: //webapiexposedusingapigee. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://mywebsite.in' is therefore not allowed access. The response had HTTP status code 502.
When I checked in Fiddler i got following fault string.
"faultstring=Received 405 Response without Allow Header"
and warning as :
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http:// test.apigee.net/v1/selectop/myapi. This can be fixed by moving the resource to the same domain or enabling CORS.
I had added following headers on APIGEE:
<Header name="Access-Control-Allow-Origin">*</Header>
<Header name="Access-Control-Allow-Credentials">true</Header>
<Header name="Access-Control-Allow-Headers">Origin, X-Requested-With, Content-Type, Accept</Header>
<Header name="Access-Control-Max-Age">3628800</Header>
<Header name="Access-Control-Allow-Methods">GET, PUT, POST, DELETE, OPTION</Header>
Any help on this is appreciated.
Thanks.
If you have correct CORS setup at WebAPI endpoint, it will accept the request. I am not familiar with APIGEE, but this link lists the steps to enable:http://apigee.com/docs/api-services/content/adding-cors-support-api-proxy.
You need to specify to use xdomain to send headers in angular js:
app.factory('contactService', ['$http', function ($http) {
var serviceFactory = {};
var _getItems = function () {
$http.defaults.useXDomain = true;
delete $http.defaults.headers.common['X-Requested-With'];
return $http.get('http://adaljscors.azurewebsites.net/api/contacts');
};
serviceFactory.getItems = _getItems;
return serviceFactory;
}]);

Why does the preflight OPTIONS request of an authenticated CORS request work in Chrome but not Firefox?

I am writing a JavaScript client to be included on 3rd party sites (think Facebook Like button). It needs to retrieve information from an API that requires basic HTTP authentication. The simplified setup looks like this:
A 3rd party site includes this snippet on their page:
<script
async="true"
id="web-dev-widget"
data-public-key="pUbl1c_ap1k3y"
src="http://web.dev/widget.js">
</script>
widget.js calls the API:
var el = document.getElementById('web-dev-widget'),
user = 'token',
pass = el.getAttribute('data-public-key'),
url = 'https://api.dev/',
httpRequest = new XMLHttpRequest(),
handler = function() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
console.log(httpRequest.responseText);
} else {
console.log('There was a problem with the request.', httpRequest);
}
}
};
httpRequest.open('GET', url, true, user, pass);
httpRequest.onreadystatechange = handler;
httpRequest.withCredentials = true;
httpRequest.send();
The API has been configured to respond with appropriate headers:
Header set Access-Control-Allow-Credentials: true
Header set Access-Control-Allow-Methods: "GET, OPTIONS"
Header set Access-Control-Allow-Headers: "origin, authorization, accept"
SetEnvIf Origin "http(s)?://(.+?\.[a-z]{3})$" AccessControlAllowOrigin=$0
Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Note that the Access-Control-Allow-Origin is set to the Origin instead of using a wildcard because I am sending a credentialed request (withCredentials).
Everything is now in place to make an asynchronous cross-domain authenticated request, and it works great in Chrome 25 on OS X 10.8.2. In Dev Tools, I can see the network request for the OPTIONS request before the GET request, and the response comes back as expected.
When testing in Firefox 19, no network requests appear in Firebug to the API, and this error is logged in the console: NS_ERROR_DOM_BAD_URI: Access to restricted URI denied
After much digging, I found that Gecko doesn't allow the username and password to be directly in a cross-site URI according to the comments. I assumed this was from using the optional user and password params to open() so I tried the other method of making authenticated requests which is to Base64 encode the credentials and send in an Authorization header:
// Base64 from http://www.webtoolkit.info/javascript-base64.html
auth = "Basic " + Base64.encode(user + ":" + pass);
...
// after open() and before send()
httpRequest.setRequestHeader('Authorization', auth);
This results in a 401 Unauthorized response to the OPTIONS request which lead to Google searches like, "Why does this work in Chrome and not Firefox!?" That's when I knew I was in trouble.
Why does it work in Chrome and not Firefox? How can I get the OPTIONS request to send and respond consistently?
Why does it work in Chrome and not Firefox?
The W3 spec for CORS preflight requests clearly states that user credentials should be excluded. There is a bug in Chrome and WebKit where OPTIONS requests returning a status of 401 still send the subsequent request.
Firefox has a related bug filed that ends with a link to the W3 public webapps mailing list asking for the CORS spec to be changed to allow authentication headers to be sent on the OPTIONS request at the benefit of IIS users. Basically, they are waiting for those servers to be obsoleted.
How can I get the OPTIONS request to send and respond consistently?
Simply have the server (API in this example) respond to OPTIONS requests without requiring authentication.
Kinvey did a good job expanding on this while also linking to an issue of the Twitter API outlining the catch-22 problem of this exact scenario interestingly a couple weeks before any of the browser issues were filed.
This is an old post but maybe this could help people to complete the CORS problem. To complete the basic authorization problem you should avoid authorization for OPTIONS requests in your server. This is an Apache configuration example. Just add something like this in your VirtualHost or Location.
<LimitExcept OPTIONS>
AuthType Basic
AuthName <AUTH_NAME>
Require valid-user
AuthUserFile <FILE_PATH>
</LimitExcept>
It was particular for me. I am sending a header named 'SESSIONHASH'. No problem for Chrome and Opera, but Firefox also wants this header in the list "Access-Control-Allow-Headers". Otherwise, Firefox will throw the CORS error.

Categories

Resources