Three Ways of Dealing with CORS

What is CORS and why do we need it?

AJAX has been popular for over 10 years now, and is a part of almost any web site that is anything more than a static display case for a digital brochure.

Requests from in-page script languages such as JavaScript have to adhere to the same-origin policy - they can by default only request things over the network from the same site they were loaded themselves. Complete domain, protocol and port must match, otherwise the browser will not allow the request.

The point of the same-origin policy is so that code from any site you visit can't access resources on any other site you have access to - you wouldn't want any random site you visit to be able to access all of your Facebook data just because you're logged into Facebook on another tab would you?

But sometimes, it's completely valid for site A to allow connections from scripts loaded from site B - for instance when A is myapp.mysite.com and B is api.mysite.com. CORS - Cross-origin resource sharing - will help with this scenario. But it's not always simple to get in place.

1. Just Implement It

CORS protection is mainly a server-side issue - the server you're connecting to (api.mysite.com) from a different domain (myapp.mysite.com) must allow the connection. It will do so by replying with a special header:

Access-Control-Allow-Origin: myapp.mysite.com

This allows browsers to connect to myapi.mysite.com if the files were loaded from myapp.mysite.com. The server must also respond in the same way to OPTIONS request - since any "complex" POST or DELETE requests are preflighted with an OPTIONS request.

  • Pros: this is the correct way of doing it.
  • Cons: not supported by all browsers. In particular, IE9 and earlier IEs do not support CORS.

There are plugins/modules that can help you in implement CORS in ASP.NET, NancyFX, NodeJS/Express and many more.

2. Use jsonp instead

Jsonp is a hack where you can inject content from a server into your page by using a special script tag. The src attribute of script tags don't have the same-origin limitation that requests made by scripts. So if your server returns a function with the data in it, you can use the script src to get the data from any domain without CORS.

On the page:

<script src="http://myapi.mysite.com/getData/123">
	function parseData(json) {
    	// logic here
    }
</script>

The server would return something like:

parseData({ name: "John Smith", department: "IT" });
  • Pros: works in all browsers
  • Cons: is actually a hack, and has some security implications - the server can send any JavaScript code so you really need to trust it and its security. The server must also be aware of how the client wants the data (wrapped in a function available on the client etc.) making it not as generic, although this can be solved with special request headers. And most importantly, JSONP does not support POST and DELETE.

3. Server-side proxy

By providing a server-side proxy that relays all API calls from the web application server to the API the client can make all the calls to its own server, never violating the same-origin policy.

So a call like:

http://myapp.mysite.com/api/users

Would be relayed server-side to:

http://api.mysite.com/users

You can either create the proxy in code in the site itself, our use a separate proxy server like nginx in front of the website to handle all the relaying.

  • Pros: works with every browser, handles POST and DELETES
  • Cons: needs another component, either a stand-alone proxy server or code written by you that needs to handle relaying of authentication, content sent in chunks etc. It also introduces extra latency, since all API requests need to be sent to the web app server and then to the API.

So which one do I choose?

The right way to do CORS (or to get around the same-origin policy to be more specific) depends entirely on which clients you need to support.

  • If you want clean code in both API and web applications and clients are only modern browsers: implement CORS
  • If you need to support older or non-standard browsers and your API is read only (GETs), JSONP is a viable alternative
  • If you need to support older browers but want a fully-fledged READ/WRITE API with clean code, use a server-side proxy.

Good luck!

comments powered by Disqus