Proxy server JavaScript enabled

Cross-Domain requests in Javascript

If you are developing a modern web-based application, chances are you:

  1. Are using javascript on the client side.
  2. Need to integrate with services that are not completely under your control (or that reside in a different “origin”).
  3. Have been confronted by this error message in your browser’s console:

XMLHttpRequest cannot load . No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '' is therefore not allowed access.

Every time I need to integrate a web app with some external service or some server-side API I have no complete control over, I bump into this error. Google has not yet provided me with a concise description of the problem or an overview of alternatives to perform Cross-Domain requests, so this post will serve as a personal future reference.

The origin of a page is defined by its protocol, host and port number. For example, the origin of this page is (‘http’, ’’, 80). Resources with the same origin have full access to each other. If pages A and B share the same origin, Javascript code included on A can perform HTTP requests to B’s server, manipulate the DOM of B or even read cookies set by B. Note that the origin is defined by the source location of the webpage. To clarify: a javascript source file loaded from another domain (e.g. a jQuery referenced from a remote CDN) will run in the origin of the HTML that includes the script, not in the domain where the javascript file originated from.

For Cross-Origin HTTP requests in specific, the SOP prescribes the following general rule: Cross-Origin writes are allowed, Cross-Origin are not. This means that if A and C have a different origin, HTTP requests made by A will be received correctly by C (as these are “writes”), but the script residing in A will not be able to read any data -not even the response code- returned from C. This would be a Cross-Origin “read” and is blocked by the browser resulting in the error above. In other words, the SOP does not prevent attackers to write data to their origin, it only disallows them to read data from your domain (cookie, localStorage or other) or to do anything with a response received from their domain.

The SOP is a Very Good Thing™. It prevents malicious script from reading data of your domain and sending it to their servers. This means that some script kiddie will not be able to steal your cookies that easily.

Sometimes however, you have to consciously perform Cross-Domain requests. A heads up: This will require some extra work.

Examples of legitimate Cross-Domain requests are:

  • You have to integrate with a third-party service (like a forum) that has a REST API residing in a different origin.
  • Your server-side services are hosted on different (sub)domains.
  • Your client-side logic is served from a different origin than your server-side service endpoints.

Depending on the amount of control you have over the server-side, you have multiple options to enable Cross-Domain requests. The possible solutions I will discuss are: JSONP, the use of a server-side proxy and CORS.

There are other alternatives, the most widely used being a technique using iframes and window.postMessage. I will not discuss it here, but for those interested an example can be found here.

Example code

I wrote some code to try out the different approaches discussed in this post. You can find the full code on my github. They should be easy to run locally if you want to experiment with them yourself. The examples each host 2 websites, a site in origin (‘http’, ‘localhost’, 3000) and one in (‘http’, ‘localhost’, 3001). These are different origins, so requests from 3000 to 3001 are considered Cross-Domain requests and are blocked by the browser by default.

Example of a failing Cross-Origin request

Consider the following scenario: a page with origin A want to perform a GET request to a page with origin B. This is what happens:

The browser issues this request correctly to the server:

GET / HTTP/1.1

The server returns the response:

HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Content-Length: 57 { "response": "This is data returned from the server" }


Related posts:

  1. Proxy server Streaming
  2. Proxy server and Port Number
  3. Proxy server with JavaScript