Amazon CloudFront Distribution & Forcing Download Behavior

AWS Management Console

When using CloudFront to distribute content stored with Amazon S3, you may at times want to force the browser to download the content rather than display it in the browser. I ran into this scenario when building Cloudbeam.

Cloudbeam generates signed URLs in order to serve private content to authorized recipients. The purpose of the application is to allow each recipient a single download of the content. I wanted to avoid the browser simply displaying the content inline. To accomplish this, I used the query string response-content-disposition=attachment in the signed URL. However, the content was still frequently being displayed in the browser rather than downloaded. What was going wrong?

Eventually, I came across this webpage and had an a-ha moment. The signed URL generated by our application was a CloudFront URL. The content served by our CloudFront distribution came from a private S3 bucket. It turns out, the query string response-content-disposition was not being forwarded from CloudFront to S3. Now that I understood the problem, I was able to find an easy solution.

It was necessary to whitelist the query string so that it would be forwarded to S3 and the response would have the appropriate content disposition. After doing so, the application functioned as desired. Each time the user was redirected to their unique signed URL, the content automatically began to download to the user’s device. Here are the steps:

  1. Visit your CloudFront console on AWS
  2. Select your distribution
  3. Select the ‘Behaviors’ tab
  4. Select the behavior list item and click ‘Edit’
  5. Click ‘Create a new policy’ near the heading ‘Cache Policy’
  6. Under ‘Cache key contents’ > ‘Query strings’ > ‘Whitelist’ add response-content-disposition.
  7. Save your new policy
  8. Voilá!

Your application should now behave as desired. Here’s a photo of what the query string white list looks like in my cache policy:

I spent a great deal of time addressing this issue and had trouble finding a helpful solution on the web. I hope that these instructions help someone struggling with the same issue in the future.