As far as I know, you cannot use canvas.toDataURL() on a tainted canvas (i.e. cross-origin). Looking at this example it seems the tiles are coming from different origin (tile.openstreetmap.org). How did OL3 managed to use toDataURL() in this case?
I tried monitoring network traffic and it seems no proxy are being used to circumvent cross-origin rules.
Best Answer
TLDR; Add crossOrigin: 'anonymous' to your source params.
This took awhile for me to dig down to but I think I have the answer. Assuming your tile server is not in your domain, and that it is providing the Access-Control-Allow-Origin:* response header as mine was.
The key is the OSM source they use. If you take a look at the documentation for ol.source.OSM you can see that there is a crossOrigin option (which defaults to 'anonymous' for osm)
This got me looking into the source for the tile source, I am using WMTS primarily but it didn't seem like these were defaulting to 'anonymous' instead requiring the dev to set this in the options for the given source.
Adding crossOrigin: 'anonymous' to my source options fixed this problem for me.
Adding this parameter changed my request headers to include one parameter:
Which as far as I can tell allows it to pass the CORS resource sharing test. Just not sure if this is due to 3 now being able to be checked, or more probably that it sets the omit credentials flag in the ajax request thus passing step 2.