Downloading resources in HTML5 a[download] may not work as expected

HTML anchor tag can’t download resources from a different origin, learn how I fixed this in my GIF app

Jude Agboola
Charisol Community
3 min readOct 8, 2019

--

Hyperlink download attribute

HTML5 allows us to add a download attribute with an optional value to indicate that the resource should be downloaded onto the user’s device.

However, as of late 2018, clicking the link won’t trigger a download if the resource to be downloaded wasn’t served from the same origin or same server so to say. Apparently, this restriction is a security measure.

Attackers may exploit your users by planting malicious download links into your website, so this is a security measure by the browser guys to prevent that.

Quick example

A hyperlink on https://www.facebook.com cannot download an image(or any resource) that was served from https://www.google.com. They are not of the same origin 🤷🏿‍♂️

A possible use case scenario

This was a big issue while I was building a simple GIF app that uses the Giphfy translate API to convert some text into a GIF.

In turn, I wanted the user to be able to download the GIF once it loads but I couldn’t! because the GIF simply wasn’t severed from the same origin as my GIF app. You can check it out here.

Solution1: Data URIs

Basically, a data URI is a base64 encoding of a resource, this means you don’t need to link to an external resource, the text itself is the resource 🙂.

Here is what it looks like

anchor tag with data URI

That gibberish text will be way more than that if the file is large. I recommend using the second solution though.

Back to the GIF app!

To incorporate this idea of data URIs, this means we have to convert the file — remote file in this case — into a data URI.

As usual, I ran to npm to search for a package that can help convert my remote GIFs into a data URI. Pweeeeh! After testing about four of them, image-data-uri worked well for me 😘 That’s not all though!

You’ll have a create a link and programmatically click it to get the file downloaded.

I created a react component to do just that, it takes in URL, once clicked and a filename as prop.

Once clicked:

  • It fetches and converts the resource into a data URI
  • creates an anchor tag, sets the href and clicks the link
download file from different origin

Solution 2: Blob (A better solution)

Instead of converting the resource to base64 we can convert it into a blob URL instead. This seems to be the perfect solution.

I totally recommend this using blob over data URI

Thanks for reading 🙂Don’t forget to share if this helped you in any way.

You can catch me on Twitter @MarvinJudeHK

The Gif app is on Github

👋🏿👋🏿👋🏿👋🏿👋🏿👋🏿

--

--

Jude Agboola
Charisol Community

Software Engineer • Occasionally write about software and anything that excites me.