CORS isn’t just for XHR

Cross Origin Resource Sharing (CORS) is what allows XHR (i.e. Ajax) requests to go cross domain. It’s a simple header response to the XHR request that says “yes, you can complete your request”, looking like this (if we allowed any client to place an XHR request against our service):

Access-Control-Allow-Origin: *

Should you be adding this header to your existing API services? Yes.

If you want more details on how it works check out this HTML5 Rocks article and make sure to watch out for preflight issues.

But this post isn’t about CORS for XHR, it’s about CORS for images. CORS for images is important for remixing content and sites such as Flickr, Instagram, Imgur and the like.

What use is CORS for images?

(As far as I know) there’s one major use case: when you’re creating a dynamic canvas image and you want to export it. The canvas element has a method called toDataURL which gives you a base64 string representing the content of the canvas.

Perhaps you’re creating a collage of your flickr photos and want to print that collage out. More specifically, in my case, I’ve been taking a photo a day for 3 years, and I wanted to print the entire collection out on a material canvas. I use the canvas API to generate my image, but I can’t export it.

That’s to say, if you use canvas API method drawImage to paint a flickr photo (perhaps even your own) on to a canvas element, you can’t use getImageData to further manipulate the pictures, nor can you use toDataURL because the url your script executed on is not the same origin* as the flickr photo.

* origin, which is made up of the protocol, host and port number.

The solution to allowing us to export our canvas creations is to enable CORS from the source origin. Simply adding the Access-Control-Allow-Origin header when an image requests origin rights.

So in my case, where I wanted to generate a file to be sent to the printers, I moved my code to using Node.js (which I’ll post about in detail another day). Couldn’t do the export in the browser – but I should have been able to.

How to request images with CORS

You have to set the crossOrigin attribute, which can be set via HTML attributes or via JavaScript.

A blank value (as an HTML attribute) has the default value of anonymous – which is likely what you want. Alternatively you can set this to use-credentials which sets the credentials request header – which the server can use to decide whether you have rights to the content.

When the CORS headers are sent back from the server for an image, and that image is used on a canvas, the origin-clean flag is true, and we are able to remix the content as we please.

Below you can see a simple working example. The script reads the image element, draws and scales it to a new canvas, then creates a circular version of the picture, and it’s then exported to a new real image element, and finally the original image is replaced with the cirlified image. The source image is hosted on http://rem.io (the <img> element with the crossOrigin attribute at the top of the HTML) but the image remixing is happening on http://jsbin.com (as an embed on this site via an iframe). This is all possible with CORS support.

canvas resizer

Go forth!

So if you happen to work at a company, or know someone that works at a company that hosts user images – please please add CORS support to your images (if an origin header is sent in the request).

There’s some good discussion going on over at Google+ whereby Matle Ubl disagrees that you should slap on a whitelist star rule. Worth reading too.

Go, go make that change, now!

5 Responses to “CORS isn’t just for XHR”

  1. Came across this when I wanted to use canvas in a Facebook app to allow users to create a cover photo with their images. Turns out FB only supports CORS on profile pictures, but our rep told us that they have plans for eventually extending this to all images.

    So for this project, we had to do the cover photo piece in Flash.

  2. I recently blogged about something similar [1] in the context of cross-domain scripts and window.onerror. By default, most modern browsers do not pass any information about errors to window.onerror if the script is loaded from across domains. This turns out to be a nasty problem if you are tracking your site’s JS errors using window.onerror.

    However, you can use CORS and a little tweak to the script tag to make it possible to track errors for x-domain scripts. This has shipped with Firefox already, and has landed in WebKit, so is expected to be rather widely available soon.

    So, I would suggest that people should also add CORS headers to their scripts as well, not just to images and API calls.

    1. http://blog.errorception.com/2012/12/catching-cross-domain-js-errors.html

  3. Nice writeup. Spotted a typo: “cirlified”.

    See also: http://zeke.heroku.com/blog/2012/10/11/s3-cors-canvas/

  4. To easily access images that are not CORS enabled, you can always create a simple node server that will proxy requested image to you (using mikeal’s request module) with added “access-control-allow-origin” header.

    var http    = require('http');
    var request = require('request');
    http.createServer(function (req, res) {
      if(req.url.match(/path=(.*)/)) {
        res.setHeader("access-control-allow-origin", "*");
        request.get(req.url.match(/path=(.*)/)[1]).pipe(res);
      }else{
        res.statusCode = 404; res.end();
      }
    }).listen(8000);

    And then in your html you just do

    <img src="http://localhost:8000/path?=http://your.image.url.here " crossOrigin>

  5. I always encounter the error on Google Chrome : “Cross-origin image load denied by Cross-Origin Resource Sharing policy.”, what’s the worse is I can’t catch it, do you have any better solution?

Leave a Reply
Not required

CODE: Please escape code and wrap in <pre><code>, doing so will automatically syntax highlight