AngularJS Refused to set unsafe header "Cookie" - javascript

I am using an AngularJS application to make a call to an API using $http. The call to $http is originating from localhost:9000. The API is endpoint is available at localhost:9100/API/v1.0/context...
I am getting an error message saying "Refused to set header Cookie". From what I have read, the browser sets these headers for security reasons and these cannot be configured. According to the similar question heresimilar question here, I have tried enabling crossDomain:true and withCredentials:true but to no effect.
Any answer on why this is happening would be appreciated.
EDIT: Here is the code
$http({
method: method,
url: urlpoint,
headers:headers,
params: query,
crossDomain: true
})
.success(function(data, status, headers, config) {
if (!data || data.length == 0)
data = $rootScope.getLocaleValue("EMPTY_RESPONSE");
operation.result.data = data;
$scope._afterMakeTestCall(operation, status,
headers, config);
});
And in the headers field, I have set
headers['Cookie'] = 'cookieValue="something";';

After a long time of searching, I came across references stating that browser will not allow to set the Cookie header due to security vulnerabilities. It can only be done through headless browsers.

Related

How to send client side cookies (javascript) to server side (node.js) using Microsoft Bot Framework Directline API? [duplicate]

I am working on an internal web application at work. In IE10 the requests work fine, but in Chrome all the AJAX requests (which there are many) are sent using OPTIONS instead of whatever defined method I give it. Technically my requests are "cross domain." The site is served on localhost:6120 and the service I'm making AJAX requests to is on 57124. This closed jquery bug defines the issue, but not a real fix.
What can I do to use the proper http method in ajax requests?
Edit:
This is in the document load of every page:
jQuery.support.cors = true;
And every AJAX is built similarly:
var url = 'http://localhost:57124/My/Rest/Call';
$.ajax({
url: url,
dataType: "json",
data: json,
async: true,
cache: false,
timeout: 30000,
headers: { "x-li-format": "json", "X-UserName": userName },
success: function (data) {
// my success stuff
},
error: function (request, status, error) {
// my error stuff
},
type: "POST"
});
Chrome is preflighting the request to look for CORS headers. If the request is acceptable, it will then send the real request. If you're doing this cross-domain, you will simply have to deal with it or else find a way to make the request non-cross-domain. This is why the jQuery bug was closed as won't-fix. This is by design.
Unlike simple requests (discussed above), "preflighted" requests first
send an HTTP request by the OPTIONS method to the resource on the
other domain, in order to determine whether the actual request is safe
to send. Cross-site requests are preflighted like this since they may
have implications to user data. In particular, a request is
preflighted if:
It uses methods other than GET, HEAD or POST. Also, if POST is used to send request data with a Content-Type other than
application/x-www-form-urlencoded, multipart/form-data, or text/plain,
e.g. if the POST request sends an XML payload to the server using
application/xml or text/xml, then the request is preflighted.
It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)
Based on the fact that the request isn't sent on the default port 80/443 this Ajax call is automatically considered a cross-origin resource (CORS) request, which in other words means that the request automatically issues an OPTIONS request which checks for CORS headers on the server's/servlet's side.
This happens even if you set
crossOrigin: false;
or even if you ommit it.
The reason is simply that localhost != localhost:57124. Try sending it only to localhost without the port - it will fail, because the requested target won't be reachable, however notice that if the domain names are equal the request is sent without the OPTIONS request before POST.
I agree with Kevin B, the bug report says it all. It sounds like you are trying to make cross-domain ajax calls. If you're not familiar with the same origin policy you can start here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Same_origin_policy_for_JavaScript.
If this is not intended to be a cross-domain ajax call, try making your target url relative and see if the problem goes away. If you're really desperate look into the JSONP, but beware, mayhem lurks. There really isn't much more we can do to help you.
If it is possible pass the params through regular GET/POST with a different name and let your server side code handles it.
I had a similar issue with my own proxy to bypass CORS and I got the same error of POST->OPTION in Chrome. It was the Authorization header in my case ("x-li-format" and "X-UserName" here in your case.) I ended up passing it in a dummy format (e.g. AuthorizatinJack in GET) and I changed the code for my proxy to turn that into a header when making the call to the destination. Here it is in PHP:
if (isset($_GET['AuthorizationJack'])) {
$request_headers[] = "Authorization: Basic ".$_GET['AuthorizationJack'];
}
In my case I'm calling an API hosted by AWS (API Gateway). The error happened when I tried to call the API from a domain other than the API own domain. Since I'm the API owner I enabled CORS for the test environment, as described in the Amazon Documentation.
In production this error will not happen, since the request and the api will be in the same domain.
I hope it helps!
As answered by #Dark Falcon, I simply dealt with it.
In my case, I am using node.js server, and creating a session if it does not exist. Since the OPTIONS method does not have the session details in it, it ended up creating a new session for every POST method request.
So in my app routine to create-session-if-not-exist, I just added a check to see if method is OPTIONS, and if so, just skip session creating part:
app.use(function(req, res, next) {
if (req.method !== "OPTIONS") {
if (req.session && req.session.id) {
// Session exists
next();
}else{
// Create session
next();
}
} else {
// If request method is OPTIONS, just skip this part and move to the next method.
next();
}
}
"preflighted" requests first send an HTTP request by the OPTIONS method to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
Consider using axios
axios.get( url,
{ headers: {"Content-Type": "application/json"} } ).then( res => {
if(res.data.error) {
} else {
doAnything( res.data )
}
}).catch(function (error) {
doAnythingError(error)
});
I had this issue using fetch and axios worked perfectly.
I've encountered a very similar issue. I spent almost half a day to understand why everything works correctly in Firefox and fails in Chrome. In my case it was because of duplicated (or maybe mistyped) fields in my request header.
Use fetch instead of XHR,then the request will not be prelighted even it's cross-domained.
$.ajax({
url: '###',
contentType: 'text/plain; charset=utf-8',
async: false,
xhrFields: {
withCredentials: true,
crossDomain: true,
Authorization: "Bearer ...."
},
method: 'POST',
data: JSON.stringify( request ),
success: function (data) {
console.log(data);
}
});
the contentType: 'text/plain; charset=utf-8', or just contentType: 'text/plain', works for me!
regards!!

angularJS sending OPTIONS instead of POST

Im stuck at this 2 days I can not find a solution.
When im doing an AngularJS POST it Sends OPTIONS in the header and returns error from the API the code looks like this nothing special.
$http.defaults.headers.post["Content-Type"] = "application/json";
$http.post(URL, JSON.stringify(data)).
success(function(data, status, headers, config) {
alert(data);
error(function(data, status, headers, config) {
console.log("Error");
});
CORS is enabled on the API it has the Headers, when i do POST with fiddler or POSTMan in Chrome it works fine only when i use angularJS post it won't go thru.
why do i get OPTIONS /SubmitTicket HTTP/1.1 instead of POST?
What do i need to do to POST ? I have read about it it says something like CORS is adding OPTIONS header but why?
When you invoke the CORS requests, the browser always sends the OPTIONS request to server to know what methods are actually allowed. So this is the desired behaviour. This is so called: "Preflighted request", see: http://www.nczonline.net/blog/2010/05/25/cross-domain-ajax-with-cross-origin-resource-sharing/ (section: "Preflighted requests")
Therefore in your case, you have to allow the OPTIONS method in 'Access-Control-Allow-Methods' header of your CORS filter.
My understanding is that angular initially sends an OPTIONS request to the server in order to ask the server if the full request is permissable.
The server will then respond with Headers specifying what is and is not allowed.
I guess this might be an issue with the server returning the wrong CORS headers.
You said that the server returns an error please post that error here.
See Preflighted CORS request at: http://www.staticapps.org/articles/cross-domain-requests-with-cors
and
AngularJS performs an OPTIONS HTTP request for a cross-origin resource
// Simple POST request example (passing data) :
$http.post('/someUrl', {msg:'hello word!'}).
success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
Should only need to do this code to get it to work:
angular.module('TestApp', [])
.factory('someService', ['$http', someService]);
function someService() {
var service = {
save: save
};
var serviceUrl = '/some/Url';
return service;
function save(data) {
$http.post(serviceUrl, data)
.success(function(data, status, headers, config) {
alert(data);
})
.error(function(data, status, headers, config) {
console.log("Error");
});
}
}
Then pull your someService into your controller and use:
someService.save(data);

ngAutoComplete with Google Suggest api

AngularJS has ngAutoComplete that works with Google place perfectly.
How can I make it work with Google Suggest API (the suggested keywords when typing in Google Search input box)? Is there something out of the box?
If not, what is the best way to implement it? (if I need my own API interface - how should I make the connection)?
EDITED
Google Suggest API will return XML for the following call. If I want to return JSON it needs to be passed via my server side to translate it. It could also be an option if you suggest so
http://google.com/complete/search?output=toolbar&q=theory&gl=in
You can add this to the remote-url -
https://www.google.com/s?sclient=psy-ab&biw=1242&bih=395&q=ThisIsTheSearchString&oq=&gs_l=&pbx=1&bav=on.2,or.r_cp.&bvm=bv.93112503,d.cWc&fp=160df26a97fa030e&pf=p&sugexp=msedr&gs_rn=64&gs_ri=psy-ab&tok=_1hxlqgFnvRgVdHXR4t-nQ&cp=10&gs_id=51&xhr=t&es_nrs=true&tch=1&ech=37&psi=O5FTVZiMAfPisASwnYH4Cg.1431540027601.1
Make ThisIsTheSearchString a var that changes on key stroke. Before you put the url into the ngAutoComplete make sure to encode the string - escape(ThisIsTheSearchString); This will help if there are any white spaces in the search.
I got the URL by going to google and watching the network tab. It will return a .txt file that you will have to read. Also you will need a regex to compile the file.
Updated Version (Custom Directive ngGoogleSuggest)
click Plunker
Directive performs much better because on keyup performs a http call to GoogleSuggest API
elem.bind('keyup', scope.search);
Markup:
<div data-ng-google-suggest ng-model="Search"></div>
Note: I plan to make a GitHub repo for ngGoogleSuggest after it has been tested a bit more
Screen Shots
Calling Google Search API
End Point: 'http://suggestqueries.google.com/complete/search
for JSON response (not XML), add param &client=firefox
Uri Encoded search Parameter
use JSONP protocol by adding ?callback=JSON_CALLBACK to avoid Access-Control-Allow-Origin Error
example $http call
scope.search = function() {
// If searchText empty, don't search
if (scope.searchText == null || scope.searchText.length < 1)
return;
var url = 'http://suggestqueries.google.com/complete/search?';
url += 'callback=JSON_CALLBACK&client=firefox&hl=en&q='
url += encodeURIComponent(scope.searchText);
$http.defaults.useXDomain = true;
$http({
url: url,
method: 'JSONP',
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS, PUT',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}).
success(function(data, status, headers, config) {
// Api returns [ Original Keyword, Searches[] ]
var results = data[1];
if (results.indexOf(scope.searchText) === -1) {
data.unshift(scope.searchText);
}
scope.suggestions = results;
scope.selectedIndex = -1;
}).
error(function(data, status, headers, config) {
console.log('fail');
// called asynchronously if an error occurs
// or server returns response with an error status.
});

AngularJS: Cannot send POST request with appropiate CORS headers

I'm creating a web app using AngularJS. To test it, I'm running the app in a NodeJS server, using angular-seed template.
In this app, I need to send a JSON message to another host, via POST request, and get the response, so, I'm using CORS.
My request is done by implementing a service that uses AngularJS http service (I need the level of abstraction that $http provides. So, I don't use $resource).
Here, my code. Please pay attention to the fact that I modify $httpProvider to tell AngularJS to send its requests with the appropriate CORS headers.
angular.module('myapp.services', []).
// Enable AngularJS to send its requests with the appropriate CORS headers
// globally for the whole app:
config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
/**
* Just setting useXDomain to true is not enough. AJAX request are also
* send with the X-Requested-With header, which indicate them as being
* AJAX. Removing the header is necessary, so the server is not
* rejecting the incoming request.
**/
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}
]).
factory('myService', function($http) {
return {
getResponse: function() {
var exampleCommand = JSON.stringify({"foo": "bar"});
// This really doesn't make a difference
/*
var config = {headers: {
'Access-Control-Allow-Origin':'*',
'Access-Control-Allow-Headers': 'Content-Type, Content-Length, Accept',
'Content-Type': 'application/json'
}
};
*/
//return $http.post(REMOTE_HOST, exampleCommand, config).
return $http.post(REMOTE_HOST, exampleCommand).
success(function(data, status, headers, config) {
console.log(data);
return data;
}).
error(function (data, status, headers, config) {
return {'error': status};
});
}
}
});
The problem is I can't make it work. I always get this error message:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at REMOTE_HOST. This can be fixed by moving the
resource to the same domain or enabling CORS.
But if I do a simple jQuery AJAX call like this:
$.ajax(REMOTE_HOST,
{
dataType: "json",
type: "POST",
data: exampleCommand,
success: function(data) { console.log(data); },
error: function(request, textStatus, errorThrown) { console.log("error " + textStatus + ": " + errorThrown);}
});
It works fine.
So, my questions:
- How do I allow cross-site requests in an AngularJS running under NodeJS?
UPDATE: Thanks to Dayan Moreno Leon's response.
My problem is I need to add cors support to my server. I'm using NodeJS http-server for development and lighttpd for production.
- Why does the simple jQuery POST request work but AngularJS POST request doesn't?
I guess jQuery AJAX requests are cross-domain by default. Not really sure yet.
Many thanks in advance
CORS is not handled on the client but in the server you need to allow CORS on your nodejs app where your angular app is trying to POST. you can try using cors module if you are using express
https://www.npmjs.org/package/cors
other whise you need to check for the options method and return 200 as a response
http://en.wikipedia.org/wiki/Cross-origin_resource_sharing
Why does the simple jQuery POST request work but AngularJS POST request doesn't?
jQuery uses simple requests while AngularJS uses preflighted requests
In your angular code you can add set Content-Type to application/x-www-form-urlencoded and encode your data using $.param

Angular simple JSON request

this will probably make me look like a total beginner and I am when it comes to angular, but here's my question:
I'm trying to make a simple request to a .JSON api but I just keep getting the error status code 0.
var dataUrl = 'http://www.reddit.com/r/pics/comments/1ua1nb/.json?limit=2';
$http({method: 'GET', url: dataUrl}).
success(function(data, status, headers, config)
{
window.alert('success:' + status);
}).
error(function(data, status, headers, config) {
window.alert('error:' + status);
});
Update:
I checked the javascript console via the browser and got these error messages:
event.returnValue is deprecated. Please use the standard event.preventDefault() instead.
Failed to load resource: the server responded with a status of 501 (Not Implemented) http://www.reddit.com/r/pics/comments/1ua1nb/.json?limit=2
Failed to load resource: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin ... is therefore not allowed access. http://www.reddit.com/r/pics/comments/1ua1nb/.json?limit=2
XMLHttpRequest cannot load http://www.reddit.com/r/pics/comments/1ua1nb/.json?limit=2. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin ... is therefore not allowed access.
You are trying to do a cross-domain request. This is forbidden by browser (it will only let you make requests to the same domain as your page was initially loaded from). This is not specific to angular, but just ajax requests in general.
You can read about it here:
http://en.wikipedia.org/wiki/Same-origin_policy
There are several ways around it, such as JSONP and CORS. Both require server-side support. You would have to look at the service you are calling to see which it might support.
You can read about how to do a JSONP request here:
http://docs.angularjs.org/api/ng.$http
You are not allowed to access resource on another website.
You need to use jsonp.
This is an un-tested modified code of yours, please try it to see whether it's working or not:
var dataUrl = 'http://www.reddit.com/r/pics/comments/1ua1nb/.json?jsonp=JSON_CALLBACK&limit=2';
$http.jsonp(dataUrl).
success(function(data, status, headers, config)
{
window.alert('success:' + status);
}).
error(function(data, status, headers, config) {
window.alert('error:' + status);
});
more to read:
http://en.wikipedia.org/wiki/Cross-origin_resource_sharing

Categories

Resources