I am trying to add a custom header to my angular js GET request as below:
$http({
method : 'GET',
url : s,
headers : {
"partnerId" : 221,
"partnerKey" : "heeHBcntCKZwVsQo"
}
})
But the issue is the headers are getting added to Access-Control-Request-Headers as below and I am getting 403 Forbidden response:
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:50.0)
Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/ *;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: GET
Access-Control-Request-Headers: partnerid,partnerkey
Origin: http://localhost:8080
DNT: 1
Connection: keep-alive
I also tried below changes but no luck
return $http.get(s, {
headers : {
'partnerId' : 221,
'partnerKey': 'heeHBcntCKZwVsQo'
}
})
In other related answers in SO I saw that the header partnerId and partnerKey need to be enabled in server side. But I am able to add these custom headers in POSTMAN client and other POST clients and able to get the expected response. So I guess I am missing something. Can someone guide me in this. Thanks in advance
Edit: One more thing I noted is that partnerId is replaced as partnerid while passing in the request. Not sure if that makes a difference.
If you add any headers to a scripted cross-origin request other than any CORS-safelisted request-headers, it triggers browsers to first do a CORS preflight request.
There is no way to prevent users’ browsers from doing that CORS preflight (though there are ways to get around it locally in your own browser when doing testing; for example, by using Postman).
So for users to be able to use a Web app of yours that makes scripted cross-origin requests with custom headers, the server to which those cross-origin requests go needs to be CORS-aware.
The reason Postman can make such requests without causing a preflight is, Postman’s not a browser engine—it's an extension that’s not restricted by the same-origin policy, so doesn’t need CORS.
Postman can basically do whatever curl or other such tools can do, but just within a browser UI for convenience. It’s otherwise bypassing normal Web-security features built into browsers.
Related
I am trying to understand how the whole CORS policy works. To explain my confusion, let me give you an example:
$.get("https://www.google.com", function(response) { alert(response) });
The above request will return with the following error:
XMLHttpRequest cannot load https://www.google.com/. Redirect from 'https://www.google.com/' to 'https://www.google.ca/?gfe_rd=cr&ei=TlqUWeGEH5HRXqW6utgI' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://fiddle.jshell.net' is therefore not allowed access.
Now in order for that to work, google would have to white-list https://fiddle.jshell.net.
Now, if I were to try the same thing on a restful API page, that will work. My question is really simple, Why?
Trying to analyze this, I tried hitting an API and analyzing its response:
https://apigee.com/console/bing?req=%7B%22resource%22%3A%22web_search%22%2C%22params%22%3A%7B%22query%22%3A%7B%22query%22%3A%22sushi%22%2C%22sources%22%3A%22web%22%7D%2C%22template%22%3A%7B%22format%22%3A%22json%22%7D%2C%22headers%22%3A%7B%7D%2C%22body%22%3A%7B%22attachmentFormat%22%3A%22mime%22%2C%22attachmentContentDisposition%22%3A%22form-data%22%7D%7D%2C%22verb%22%3A%22get%22%7D
Response:
HTTP/1.1 200
Date:
Wed, 16 Aug 2017 14:31:32 GMT
Content-Length: 266
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Server: Apigee Router
X-Content-Type-Options: nosniff
I came to conclusion that it must be the headers. Specifically I belive that it is this header: Content-Type: application/json; But I don't know for sure, I am trying to understand this and hoping somebody here can explain to me.
So I did 2 tests: running your code $.get("https://www.google.com", function(response) { alert(response) }); snippet from the console and requesting https://www.google.com from https://apigee.com/console/others
I think what happens in the 1st case is the fact that the request is done from the client, next request headers are sent:
:authority:www.google.com
:method:GET
:path:/?_=1502896196820
:scheme:https
accept:*/*
accept-encoding:gzip, deflate, br
accept-language:en-US,en;q=0.8
origin:https://stackoverflow.com
referer:https://stackoverflow.com/questions/45717044/understanding-page-response
user-agent:Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3187.0 Safari/537.36
x-chrome-uma-enabled:1
x-client-data:CJG2yQEIo7bJAQiMmMoBCKudygEIs53KAQjRncoBCKiiygE=
Since Google does not reply with 'Access-Control-Allow-Origin: *' - client, and in the request I have origin:https://stackoverflow.com, Chrome in my case throws CORS error.
In the 2nd test, using https://apigee.com/console/others and requesting https://www.google.com , apigee.com seems to overwrite headers and sends:
GET / HTTP/1.1
Host:
www.google.com
X-Target-URI:
https://www.google.com
Connection:
Keep-Alive
Also, from DEV console, I can see it does server to server call so no client involved in throwing CORS, thus I am getting the responses with Google page.
UPDATE:
Regarding JSON API requests, here is some interesting info from Google CloudPlatform about CORS
Note: CORS configuration applies only to XML API requests. For JSON
API requests, Cloud Storage returns the Access-Control-Allow-Origin
header with the origin of the request.
Thus, if the request is performed from the client, a client should not throw CORS errors since it gets Access-Control-Allow-Origin with the same origin it sent.
However, different APIs and clients might process requests differently. Thus, sometimes Firefox throws CORS while Chrome does not.
I got this code:
var req = new HttpRequest();
req.open("POST", "http://localhost:8031/rest/user/insert");
req.setRequestHeader("Content-type", "application/json");
req.send(json.stringify(user_map));
But, instead of sending the POST verb, when I see it in fiddler I see this:
OPTIONS http://localhost:8031/rest/user/insert HTTP/1.1
Host: localhost:8031
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://127.0.0.1:3030
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.33 (KHTML, like Gecko) Chrome/27.0.1430.0 (Dart) Safari/537.33
Access-Control-Request-Headers: origin, content-type
Accept: */*
Referer: http://127.0.0.1:3030/E:/grole/dart/Clases/Clases/web/out/clases.html
Accept-Encoding: gzip,deflate,sdch
Accept-Language: es-ES,es;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
As you can see, it is using the OPTIONS verb instead of POST?
What's going on?
The OPTIONS verb is a preflight request sent by some browsers to check the validity of cross origin requests. It pretty much checks with the server that the Origin(requester) is allowed to make the request for a specified resource. Also, depending on which headers are sent back by the server it lets the browser know which headers, methods, and resources the origin is allowed to request form the server.
The browser sends the OPTIONS request then if the server answers back with the correct headers (CORS headers) allowing the origin to make the request, you should see your POST request go through afterwards.
Note that the CORS headers must be returned on both the OPTIONS response as well as the POST response. This means your server must be able to respond to the options method on the routes you want to access across domains.
This is known as Cross-origin Resource Sharing. Mozilla has some pretty good documentation on the subject. https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS
If you have more questions let me know and I'll answer them.
One way to avoid this problem is by sending the request payload without custom headers and using formData to setup your request payload.
The following code (using the PouchDB Authentication plugin) fails because it triggers the browser to send a CORS preflight request, and CouchDB does not support the OPTIONS HTTP method.
var db = new PouchDB("http://localhost:5984/mydb");
db.login('username', 'password');
// assume the database URL and login info are valid
Here is the error (in Chrome). Note that this issue also occurs in Edge, but not in Firefox:
XMLHttpRequest cannot load http://localhost:5984/_session. Response for preflight has invalid HTTP status code 405
And here are the headers that Chrome is sending for the request (they are not significantly different in Firefox):
POST /_session HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 25
Accept: application/json
Origin: http://localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://localhost:8080/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8,es-419;q=0.6,es;q=0.4
I have already enabled CORS via the add-cors-to-couchdb Node script. Things I have tried:
Manually adding OPTIONS as a method under [cors] in my local.ini
Passing { ajax: { content_type: "text/plain" } } as the third argument to login
So, my question is:
How can I prevent the preflight request from being triggered? Looking at the MDN documentation, it doesn't seem necessary.
If the previous is not possible, how can I set my CouchDB server up to respond to preflight requests?
Hitting this same issue. Seems Chrome has recently started being a little more aggressive about sending the OPTIONS preflight.
A partial work around was to specify a specific origin in the CORS header instead of '*',
so
curl -X PUT $HOST/_config/cors/origins -d '"localhost:8080"'
or similar.
I still am getting the preflight error, but now PouchDB successfully authenticates, so I can just ignore the error.
I think the fix is to get CouchDB to respond to OPTIONS on the _session url.
Edit, more info here
https://github.com/nolanlawson/pouchdb-authentication/issues/111
With the latest PouchDB you authenticate like so:
var remote = new PouchDB("http://user:password#localhost:4984/bucket/");
How come when I go to almost any website, for example SO, if I open up the console, inject jQuery and send a cross-domain ajax request to a server I have running on my localhost, I don't get any errors as I would have expected? However, if I open up one of the webpages that I have written myself, and which is also running on my localhost (but on a different port from the one used by the server), if I try to send an ajax request from the console I get this message:
XMLHttpRequest cannot load https://localhost:10000/. Request header field My-First-Header is not allowed by Access-Control-Allow-Headers in preflight response.
The ajax request looks like:
$.ajax({
type: 'POST',
url: 'https://localhost:10000',
headers: {
"My-First-Header":"first value",
"My-Second-Header":"second value"
}
})
To be clear, my question is not about how to fix this, but rather why I am even able to make cross-domain requests from most other websites (shouldn't they be not allowed?). Do these sites have some sort of mechanism set up that automatically bypasses the restrictions?
Request headers:
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Cookie:csrftoken=lxe5MaAlb9GC5lPGQpXtSj9HvCP0QhCz; PHPSESSID=uta0nlhlh8r1uimdklmt3v3ho1
Host:localhost:10000
Referer:http://stackoverflow.com/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36
Response headers:
Content-Length:3
Content-Type:text/html
Date:Mon, 16 May 2016 06:29:03 GMT
Server:TwistedWeb/16.0.0
It seems obvious what's going on here: the browser simply handles code typed in the console differently than code run by the page itself. It makes philosophical sense that it would work that way. After all, the point of the Same-Origin Policy is to prevent XSS and CSRF attacks, and if a user opens up their console and sends cross-domain requests, they're just attacking themselves.
On the other hand, it is possible to trick users into performing XSS on themselves. If you go to Facebook and open up the console, Facebook has code that logs a warning message telling ordinary users not to paste unknown code into the console because it could be malicious. Apparently that's a problem they've seen.
This is called as CORS request.
By default all Cross Domain requests are blocked by most of the major browsers.
Most of the portals services that you are able to request cross domain does special settings in Response. If you don't provide those settings at api level then your api will be blocked for cross domain requests.
These Response settings are as follows:
Response Header Need to have access-control-allow-origin attribute.
access-control-allow-origin can specify * for every api service at global level.
access-control-allow-origin can specify specific method name for every api service separately..
I've followed the following steps:
Get the server to allow cross domain calls (with all the headers and stuff) This works
Test the server with some cross domain calls This works
Get the server to force a certificate This works
Go to a file on the server with a browser, choose the right certificate and see the file Still works
Now we get to the nice part
Combine the cross domain calls with the certificate <-- this does not work
Problem
I am getting the certificate request from the browser, but when I select the same certificate as I do when using the browser, the call is made but I get a 403 Forbidden.
Code
$.ajax({
type: "POST",
xhrFields: {withCredentials: true},
dataType: "xml",
contentType: "text/xml; charset=\"utf-8\"",
url: "https://www.myOtherServer.com/testfile.asp",
});
Any ideas?
Edit
The Access-Control-Allow-Credentials: true and the Access-Control-Allow-Origin are properly configured.
Additional information
I'm starting to think that it has something to do with the content type. When I change it to "text/html" I get a 415 error, but I do really need to send xml because it is a SOAP server.
Response headers
Access-Control-Allow-Cred... true
Access-Control-Allow-Head... Content-Type, Origin, Man, Messagetype, Soapaction, X-Test-Header
Access-Control-Allow-Meth... GET,POST,HEAD,DELETE,PUT,OPTIONS
Access-Control-Allow-Orig... https://www.mywebsite.com
Access-Control-Max-Age 1800
Cache-Control private
Content-Length 5561
Content-Type text/html; charset=utf-8
Date Wed, 19 Dec 2012 15:06:46 GMT
Server Microsoft-IIS/7.5
X-Powered-By ASP.NET
Request headers
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language nl,en-us;q=0.7,en;q=0.3
Access-Control-Request-He... content-type
Access-Control-Request-Me... POST
Cache-Control no-cache
Connection keep-alive
Host myhoast.com
Origin https://www.mywebsite.com
Pragma no-cache
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0
My best guess is that this is a problem not with your Javascript but with your CORS configuration. Did you set up your server with the Access-Control-Allow-Credentials: true header? http://www.w3.org/TR/cors/#access-control-allow-credentials-response-header
Also note that, even when the allow-credentials header is set, the browser will not allow responses to credentialed requests if Access-Control-Allow-Origin is *, according to these docs: https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS?redirectlocale=en-US&redirectslug=HTTP_access_control#Requests_with_credentials.
Edit: Since the OP has the CORS headers set up properly, the problem seems to be that the server is rejecting OPTIONS requests with a 403 status code. OPTIONS requests (known as the "preflight request") are sent before certain cross-domain requests (such as POSTs with application/xml content types), to allow the server to notify the browser of what types of requests are allowed. Since the browser doesn't see the 200 response that it expects from the OPTIONS request, it doesn't fire the actual POST request.
basicly we just have to write on htaccess
Header set Access-Control-Allow-Origin “*”
but when we need cookie etc, we had to add script on your ajax code and htaccess
i write about cross domain XHR on my blog, blog.imammubin.com/cross-domain-xhr/2014/05/28/ (Edit: site no longer exists)
hope this help..