Categories

Cross Domain AJAX Request

Posted on: October 2, 2016 by Dimitar Ivanov

A common problem for developers is a browser to refuse access to a remote resource. Usually, this happens when you execute AJAX cross domain request using jQuery or plain XMLHttpRequest. As result is that the AJAX request is not performed and data are not retrieved.

jquery ajax cross domain
Figure 1. The same-origin policy restriction in effect

Same-Origin Policy

This is a security policy who defines the rules of how a web page can access an external resource (e.g. fonts, AJAX requests). Under the same-origin policy, web browsers do not permit a web page to access resources who origin differ than that of the current page. The origin is considered to be different when the scheme, hostname or port of the resource do not match that of the page. Overcoming the limitations of same-origin security policy is possible using a technique called Cross-origin resource sharing or simply CORS.

Cross-Origin Resource Sharing

CORS is a mechanism that defines a procedure in which the browser and the web server interact to determine whether to allow a web page to access a resource from different origin.

cross domain ajax request
Figure 2. Cross domain ajax request

When you do a cross-origin request, the browser sends Origin header with the current domain value.

Origin: http://zinoui.com

When the server receives the request, check whether the origin header is within the allowed list, and sends a response with Access-Control-Allow-Origin

Access-Control-Allow-Origin: http://zinoui.com

If you want to allow access for all, use a wildcard '*'

Access-Control-Allow-Origin: *

AJAX cross domain request

1. Simple request
A simple cross-domain request is one that:

  • Does not send custom headers (such as X-PINGOTHER, etc.)
  • Only uses GET, POST or HEAD request methods

This is how the simple cross domain ajax request should looks like:

<script type="text/javascript">
// jQuery cross domain ajax
$.get("http://www.example.org/ajax.php").done(function (data) {
    console.log(data);
});

// using XMLHttpRequest
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://www.example.org/ajax.php", true);
xhr.onload = function () {
    console.log(xhr.responseText);
};
xhr.send();
</script>

2. Preflighted requests
Setting custom headers to XHR triggers a preflight request. With simple words this mean that preflight request first send an HTTP request by the OPTIONS method to the resource on the remote domain, to make sure that the request is safe to send. According W3C for non same origin requests using the HTTP GET method a preflight request is made when headers other than Accept and Accept-Language are set.

<script type="text/javascript">
// jQuery preflight request
$.ajax({
    type: "GET",
    headers: {"X-My-Custom-Header": "some value"},
    url: "http://www.example.org/ajax.php"
}).done(function (data) {
    console.log(data);
});

// XMLHttpRequest preflight request
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://www.example.org/ajax.php", true);
xhr.setRequestHeader("X-My-Custom-Header", "some value");
xhr.onload = function () {
    console.log(xhr.responseText);
};
xhr.send();
</script>

3. Request with credentials
By default, for non same origin request, browsers will not send credentials (such as HTTP Cookies, HTTP Authentication and client-side SSL certificates). A specific attribute has to be set on the XMLHttpRequest object when it is invoked.

<script type="text/javascript">
// jQuery CORS example
$.ajax({
    xhrFields: {
        withCredentials: true
    },
    type: "GET",
    url: "http://www.example.org/ajax.php"
}).done(function (data) {
    console.log(data);
});

// XMLHttpRequest
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://www.example.org/ajax.php", true);
xhr.withCredentials = true;
xhr.onload = function () {
    console.log(xhr.responseText);
};
xhr.send();
</script>

4. The Response
Let's see how the server response should look like:

<?php
// http://www.example.org/ajax.php
if (!isset($_SERVER['HTTP_ORIGIN'])) {
    // This is not cross-domain request
    exit;
}

$wildcard = FALSE; // Set $wildcard to TRUE if you do not plan to check or limit the domains
$credentials = FALSE; // Set $credentials to TRUE if expects credential requests (Cookies, Authentication, SSL certificates)
$allowedOrigins = array('http://zinoui.com', 'http://jsfiddle.net');
if (!in_array($_SERVER['HTTP_ORIGIN'], $allowedOrigins) && !$wildcard) {
    // Origin is not allowed
    exit;
}
$origin = $wildcard && !$credentials ? '*' : $_SERVER['HTTP_ORIGIN'];

header("Access-Control-Allow-Origin: " . $origin);
if ($credentials) {
    header("Access-Control-Allow-Credentials: true");
}
header("Access-Control-Allow-Methods: POST, GET, OPTIONS");
header("Access-Control-Allow-Headers: Origin");
header('P3P: CP="CAO PSA OUR"'); // Makes IE to support cookies

// Handling the Preflight
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') { 
    exit;
}

// Response
header("Content-Type: application/json; charset=utf-8");
echo json_encode(array('status' => 'OK'));
?>

Few notes:

  • A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true.
  • Gecko 11.0 (Firefox 11.0 / Thunderbird 11.0 / SeaMonkey 2.8) removed support for using the withCredentials attributes when performing synchronous requests.

Browser support

Chrome 3+, Firefox 3.5+, IE 10+, Opera 12+, Safari 4+

Editor's Note: This post was originally published in February 2015 and has been revised and updated for accuracy and comprehensiveness.

Make your website more secure by using the HTTP Headers for Wordpress, and never face a cross-origin issue again. Oh yes, it's FREE.
See also
Social sharing

If you have any questions about cross-domain AJAX requests or CORS itself, leave a comment below. And do not be shy to share this article. Thanks so much for reading!


36 Comments

Jeeva raj
I am using this code for cross domain request. The data is retrieved successfully. When i display the data it shows null message. I don’t know whats wrong with my code. pls help me..

$.ajax({
type: 'GET',
url: 'http://localhost:8080/WSwithJson/employee/1',
processData: true,
data: {},
dataType: 'json',
success: function (data) {
alert('data = '+data);
}
});
Dimitar Ivanov
Since JSON is an object, you need to convert it to string. So to display the response try using:

alert("data = " + JSON.stringify(data));

or even better:

console.log(data);
rose
i trying to get json object format like {"name":"value","name":[{"name1":"A","name":"B"}]} from other server as cross domain data received success but displaying time
console.log(data); i am getting SyntaxError: missing ; before statement
Dimitar Ivanov
@rose As I see you have a syntax error, check your syntax again or paste your code here to review.
oluwaslim
Can i load something like google.com with this
Dimitar Ivanov
@oluwaslim The only condition is that the remote server must allow access to requested resource, by sending Access-Control-Allow-Origin header. Google.com doesn't send this header.
Mike
Using the jQuery load() method, I wish to load from my website http://localhost/source, as follows the specified URL but I get an error “XMLHttpRequest cannot load… No 'Access-Control-Allow-Origin' header…”:

$('#content').load('http://localhost:8080/destination');

I can have control on the destination server, I’m not sure which solution is suitable for my case, and also just to get started… how to implement it.

Do I need to write anything in .htaccess? or add something in a separate PHP script? Etc’
Dimitar Ivanov
Dimitar Ivanov June 30, 2015 at 01:13 am
@Mike In your case localhost:8080/destination is the remote resource, so that is the place where Access-Control-Allow-Origin header must be presented in the server response. See how (use your prefered method):

// PHP
header("Access-Control-Allow-Origin: *");

// Apache (.htaccess)
Header set Access-Control-Allow-Origin "*"
Luis
Is possible a request without permission the server? Could you provide the example's file?
Dimitar Ivanov
@Luis, you do not need an access to the remote server only if the Access-Control-Allow-Origin header is already placed in the response.
Kranthi
I am accessing cross domain resource and it has one request header and am passing that.There is no credentials required but somehow when I access this it prompts for username and password.How to bypass this?
Dimitar Ivanov
@Kranthi, it seems that you've requested a remote resource who is protected with HTTP Authentication. In this case the "Authorization" header must be present in the request. See example below:

//using jQuery
$.ajax({
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', 'Basic ' + btoa('username:password'));
},
...
});
//or
$.ajax({
headers: {'Authorization': 'Basic ' + btoa('username:password')},
...
});
//using XMLHttpRequest
var xhr = new XMLHttpRequest();
...
xhr.setRequestHeader("Authorization", 'Basic ' + btoa('username:password'));
...
Erin
I have this request

var urlset = "https://hubspot-api.manobyte.com/hanson_resources_ajax/?" + dataString;
$.ajax({
type: "GET",
url: urlset,
datatype : "html",
contentType: "application/json; charset=utf-8",
success: function(response) {
$('#resource_items').hide().html(response).fadeIn(650);
}
});

And I need to pass it through the cross domain but im a bit stumped about how to do the "contentType". I tried

var xhr = new XMLHttpRequest();
var urlset = "https://hubspot-api.manobyte.com/hanson_resources_ajax/?" + dataString;
xhr.open("GET", urlset, true);
xhr.onload = function (response) {
$('#resource_items').hide().html(response).fadeIn(650);
};
xhr.send();

and it does do the onload .hide but doesn't load the content in.
Dimitar Ivanov
Hi @Erin,

If you want to send a header through the XMLHttpRequest interface, use:

xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');

* Please note that setting the Content-Type with such a value will trigger the browser to send a preflight OPTIONS request to the server.

To get the response to the request use responseText property:

xhr.onload = function () {
$('#resource_items').hide().html(xhr.responseText).fadeIn(650);
};
Gabriel
Hi Dimitar,

Thanks for your tuto.
I have questions :

I'm using Symfony2. I have a domain A : xbo.dev and a domain B : blog.xbo.dev
I want to execute an Ajax POST request from B to A function.

The request is done correctlty but Symfony doesn't consider it as a XmlHttpRequest.

In my controller, I have :

if ($request->isMethod('POST') && $request->isXmlHttpRequest()) {
//some code
}

But the "$request->isXmlHttpRequest()" return false everytime.

How can I do ?

Thanks a lot
Dimitar Ivanov
Hi @Gabriel,

Libraries like jQuery doesn't send the X-Requested-With header with cross-domain requests.
You can:

1. set the header manually (note that this will trigger a preflight request)
// jQuery
$.ajax({
beforeSend: function (xhr) {
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
}
})
// or
$.ajax({
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});
// raw javascript
var xhr = new XMLHttpRequest();
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');

In addition, you must append X-Requested-With to the list of allowed headers (server-side):

header("Access-Control-Allow-Headers: Origin, X-Requested-With");

2. If you prefer to avoid preflight requests, do a change in your code:

if ($request->isMethod('POST') && ($request->isXmlHttpRequest() || isset($_SERVER['HTTP_ORIGIN'])))
Styler
Worked for me. Thanks.
stephane
hello,

i use the :
header("Access-Control-Allow-Origin: *");
in php file for cors in jquery method $.get(
how safe is this method? can it be dangerous?
thx for answers
Dimitar Ivanov
Hi @stephane,

CORS only gives remote access to server resources. While CSRF attacks are possible regardless of CORS. Therefore, CORS is not a security risk.
stephane
thank you for responde :)
phil
awesome! thanks a lot.
it didn't work for me in a local environment using localhost:8080 as client and localhost:8000 as server. but as soon as i hosted it on a real webserver it worked :)
Octavio
Hello Dimitar

Please I need your help, I have this API

http://181.198.255.226:9810/api/apservice/GetSearchCity/?qpage=0&qcountpage=0&qcity_desc=Guayaquil

I do differents ways but nothing work

<?php
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Methods: GET");
header("Content-Type: text/plain; charset=utf-8");
?>

<script type="text/javascript">
$.ajax({

url: 'http://181.198.255.226:9810/api/apservice/GetSearchCity/?qpage=0&qcountpage=0&qcity_desc=Guayaquil',
type: 'GET',
headers: {"Content-Type":"text/plain; charset=utf-8", "Accept": "*", "Accept-Language":"es-ES,es;q=0.8"},

//dataType: 'jsonp',
success: function() { alert("Success"); },
error: function() { alert('Failed!'); }
});
</script>
Octavio
< ? php
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Methods: GET");
header("Content-Type: text/plain; charset=utf-8");
?>

< script type="text/javascript" >
$. ajax({

url: 'http://181.198.255.226:9810/api/apservice/GetSearchCity/?qpage=0&qcountpage=0&qcity_desc=Guayaquil',
//data: myData,
type: 'GET',
headers: {"Content-Type":"text/plain; charset=utf-8", "Accept": "*", "Accept-Language":"es-ES,es;q=0.8"},
//dataType: 'jsonp',
success: function() { alert("Success"); },
error: function() { alert('Failed!'); },
});
</ script >
Ratish
XMLHttpRequest cannot load https://nespreprod.service-now.com/api/now/v1/table/u_incident_rest_inbound. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. Tried even by hosting but not working but on postman it's working fine. Can you help

var Subject = $("input[name=Subject]").val();
var Detail = $("input[name=Detail]").val();
var Name = $("input[name=Name]").val();
var Email = $("input[name=Email]").val();
var Request = $( "#myselect option:selected" ).val();
var username = "something";
var password = "something";
var tarus = "tarus";
console.log(Request);
var data = JSON.stringify({u_source:"tarus", u_subject:Subject,u_detail:Detail,u_name:Name,u_email:Email,u_request:Request})

$.ajax({
url: "https://nespreprod.service-now.com/api/now/v1/table/u_incident_rest_inbound&quot;, //your api url is here
//Host: "nespreprod.service-now.com",
method: "POST",
data: data,
dataType: 'json',
crossDomain: true,
accepts: "application/json",
contentType: "application/json",
beforeSend: function(client) {
//Authorization: "Basic " + btoa(username + ":" + password);
client.setRequestHeader('Authorization', "Basic" + btoa(username + ":" + password));
client.setRequestHeader('Access-Control-Allow-Origin','http://localhost');
},
//Authorization: "Basic **************"),
success: function(response) {
alert('Email Send');
},
error: function(response) {
alert('Please Try again Later!');
}
});
gugu
I send data to cross server. But nothing changes and not displaying anything. Could you help me?

This is my code

$('#submit').submit(function(event){
event.preventDefault();

var email = $('#email').val();
var fname = $('#fname').val();
var lname = $('#lname').val();
var pwd = $('#pwd').val();
var pid = "11";
var rdo = $('input[name=rdo]').val();
var data =JSON.stringify({"email":email, "projectId":pid, "password":pwd, "firstName":fname, "lastName":lname, "allowNotification":rdo });
//var jsonData = JSON.stringify( data );
//alert(jsonData);
$.ajax({

url:'https://54.251.110.181:8181/tos-member/user/membership/register',
type: "POST",
dataType: "json",
crossDomain:true,
data: data,
accepts: "application/json",
contentType: "application/json",
success: function (data){
$(".show").text(JSON.stringify(data));
console.log("success");
},
error:function(){
alert('Error');
}

});

});
Cornelia
Hello

interesting article. I have a problem when trying to do a JQuery Ajax cross domain request.

the request is:
jQuery.ajaxPrefilter(function(options) {
if (options.crossDomain && jQuery.support.cors) {
options.url = 'https://cors-anywhere.herokuapp.com/' + options.url;
}});

jQuery.ajax({
method : "GET",
crossDomain : true,
url : "http://......",
data: {'q':'id:149727011-2',
'version':'2.2',
'start':'0',
'rows':'10',
'indent':'on'},
dataType : 'json',
headers: {"X-My-Custom-Header": "toto"},
success: function(responseData, textStatus, jqXHR) {
var value = responseData;
},
error:function (xhr, errorType, thrownError){
console.log(xhr.status);

}
}).done(function(data) {
ajaxcall = data;
});


Server response is:
Missing required request header. Must specify one of: origin,x-requested-withMissing required request header. Must specify one of: origin,x-requested-with

I used a simple html page and cors-anywhere.herokuapp.com as reverse proxy.
https://cors-anywhere.herokuapp.com/url_destination

Even though I add this header manually in the request it doesn't work.

any hints?

thanks in advance
Cornelia
Kukdip
I am trying to cross domain ajax reject but I am getting below error:
NetworkError: 405 Method Not Allowed - http://kuldip.local/api/v1/trades?term=s

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://kuldip.local/api/v1/trades?term=s. (Reason: CORS preflight channel did not succeed).

Here is my AJAX request with custom header:

jQuery.ajax({
url: "http://kuldip.local/api/v1/trades&quot;,
headers: {'api_key': '982f60641f4baab45695a50367eeb9edb42f9cc7'},
type: 'get',
data: {
term: request.term
},
success: function (data) {
response(data.data);
}
});

On other hand, PHP side, I have written like:

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE');
header('Access-Control-Allow-Headers: Authorization, X-Custom-Header');

Could you please help me? I am using Restler API framework. Also getting same error in basic authentication method.
Dimitar Ivanov
Dimitar Ivanov May 6, 2016 at 06:24 am
Hi @Kukdip,

The preflight requests use the OPTIONS method, so you must add it here:

header('Access-Control-Allow-Methods: GET, HEAD, PUT, PATCH, POST, DELETE, OPTIONS');
jess
@Dimitar lvanov
I am having trouble in here, it has been like two days. i am using phonegap, and i am trying to do ajax call to my own test server using jsonp because i tried json and did not work, on ripple and Mozilla it works perfectly, but once i build it, on my android it throws parser error..on IE as well throws the same error. this how im doing the call
type: 'GET',
url: 'http://xxx/',
data: datap,
contentType: "application/json; charset=utf-8",
headers: {"X-My-Custom-Header": "some value","X-Requested-With": "XMLHttpRequest"},

dataType: 'jsonp',
cache: false,
jsonp: 'callback',
beforeSend: function() {
// This callback function will trigger before data is sent
$.mobile.loading('show'); // This will show ajax spinner
alert( datap);
},
complete: function() {
// This callback function will trigger on data sent/received complete
$.mobile.loading('hide'); // This will hide ajax spinner
},
success: function (result) {...


and my server is smth like this....

header("Access-Control-Allow-Origin: *");
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Methods: GET, HEAD, PUT, PATCH, POST, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Authorization, X-Custom-Header');


echo $_GET['callback'] . '(' . "{'fullname' : 'Jeff Hansen',
'id':'12323',
'image': '$src'}" . ')';
please also let me know how to do a proper ajax call in phonegap app if someone knows..
Shibha
Hi,

I am trying a GET call as the following using XMLHttpRequest. But getting the following :
<html>
<head>
<script type="text/javascript">
function callService(){
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", 'https://inxs.corp.apple.com:8443/latest/signon'); // false for synchronous request
xmlHttp.setRequestHeader("cookie","myacinfo-uat=DAWTKNV2525c42407a0e6c3d201ff0a6348fadb4d0514a763f5a651135dad54b506f8828f66c47a0fdf218eebc7952607b06a0f9c9abd075aa544d2494d8df4701fd1b3839565cd7e5cc485e6fada8a1843f9b14408e2f48ebcbeec90f0b4cd65e5a98331d335cc6fa630fd2159d008ded1ee4d138130b50fa91f1104f47e8167fa0317f7d5b001b25097d2efe70ef466ee5f9ff1c572d6c17aa21d973796aaf4f23d9dc73e42d8bcedd6e8bccfe2f4c23d7d6bd13b3563165565fcc23e270ea2236188f1abb890bfc9000dc5e697ab69101e69babddebeb1022099fc30c6a3bb4c5ae9b729f10bf50e6898712a02202a6405afe62383434326261633962626663663531306663646433363564383632636636313062386330303439SRVTV2");
xmlHttp.send();
setTimeout(function(){ alert("Hello"+xmlHttp.responseText); }, 10000);
}

</script>
</head>
<body>
<p><button onclick="callService()">show</button>
</body>
<html>


XMLHttpRequest cannot load https://inxs.corp.apple.com:8443/latest/signon. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 403.

Nitin Godhani
Nitin Godhani May 18, 2016 at 03:07 am
Hello,
I am using this code

$(document).ready(function()
{
$('.button').click(function()
{
var settings =
{
"async": true,
"crossDomain": true,
"url": "https://partner-int-api.groupon.com/deals.json?country_code=AU&tsToken=AU_AFF_0207060_618029_0&division_id=sydney&filters=topcategory%3Atravel%2Ccategory%3Ahotels&offset=0&limit=20&wid=example-001",
"method": "GET",
"headers":
{
"cache-control": "no-cache",
//'Access-Control-Allow-Origin': '*',
"Content-Type" :"application/json;charset=utf-8"
}
}

$.ajax(settings).done(function (response)
{
console.log(response);
});

});

});

but give the response in warning are

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://partner-int-api.groupon.com/deals.json?country_code=AU&tsToken=AU_AFF_0207060_618029_0&division_id=sydney&filters=topcategory%3Atravel%2Ccategory%3Ahotels&offset=0&limit=20&wid=example-001. (Reason: CORS header 'Access-Control-Allow-Origin' missing).

what is the problem in this code??
Dimitar Ivanov
Dimitar Ivanov May 18, 2016 at 12:41 pm
Hi @Nitin,

It seems that Groupon API doesn't support cross-origin requests. But JSONP works well. So add this to your settings:

"dataType": "jsonp"
Dimitar Ivanov
Dimitar Ivanov May 18, 2016 at 12:48 pm
Hi @Shibha,

There is a problem with this URL, are you sure is valid?
In addition, for security reasons only the user-agent (e.g. the browser) is able to set a cookie.
Seb
Hello Dimitar, is it possible with your method when my website page load to grab a cookie on another website with "dataType": "jsonp" like you said @Nitin ? What would be the code ? Thanx :)
Phyllis
I keep getting the Cross-Origin request blocked when I use xmlhttprequest. Our web server is hosted by someone else. What kind of parameter do I ask them to set on the web server to allow Access-Control-Allow-Origin?

Phyllis
I should have given more details.

i_url='https://...mypackage.myproc?pIn=ABC';
var cors_request=createCORSRequest("get",i_url);
if (cors_request) {
cors_request.onload = function() {alert(cors.request.responseText);}
cors_request.send();
}

function createCORSrequest(method,url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
xhr.open(method,url,true);
}
return xhr;
}

Comments are closed