Presigned URLs with ExAws

Hello! I am using ExAws and the code below to make a presigned request for uploading image files to Amazon S3. All is well except that the permissions on the uploaded file are not being set to public-read:

 def make_presigned_url(bucket, path, mime_type) do
    query_params = [{"ContentType", mime_type}, {"ACL", "public-read"}]
    presign_options = [query_params: query_params]
    {:ok, presigned_url} = ExAws.Config.new(:s3) 
        |> ExAws.S3.presigned_url(:put, bucket, path, presign_options)
    presigned_url 
 end

Do you see any other mistakes?

PS. Here is .typical presigned url produced with the above:

https://s3.amazonaws.com/noteimages/jxxcarlson/carr_fire_2.jpg?ACL=public-read&ContentType=image%2Fjpeg&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAJQYJYCIAWH6DGHIQ%2F20180809%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20180809T045031Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=e6e620f563606cfea26340c0f8f402bad35a5c50a841b25d5168bccf52f6da15

I think this might simply not be possible. If you take a look at the AWS Java SDK docs, you can see that only a handful of parameters that would usually be sent as headers are supported (there is setContentMd5, setContentType, etc - but not setACL).
Also check out this GitHub issue with two possible workarounds.

Thanks, it indeed seems to be the case that one cannot set the ACL this way. Do you know if it i possible to set the bucket parameters so that uploaded files are automatically publicly readable?

What i am trying to accomplish is to allow users of my app to upload images that will be publicly readable.

You can set permissions for the entire bucket.

I got it to work, it was very simple in the end!
here’s the code

ExAws.Config.new(:s3)
|> ExAws.S3.presigned_url(
  :get,
  bucked_name,
  filename
)

This is really cool - so you don’t actually need to make a single thing public and I can get MUX.com to read a signed URL when making video for me. Will try this method, thanks!

Change your query_params to this:

query_params = [
      {"ContentType", type},
      {"x-amz-acl", "public-read"}
 ]

This Works For Me, thanks.

Thank you good sir.

I’ve been trying to set the "Content-Disposition" key to attachment via the query_params for the presigned_url in this scenario, but it doesn’t seem to be “taking”. Is there any way to do this here, that is via the ex_aws_s3 upload?

        query_params = [
        ....
          # so the browser will download this as a file
          {"ContentDisposition", "attachment"},
        ....
        ]

I managed to generate a S3 presigned download URL which behaves like a file download by setting the response-content-disposition: "attachment" header:

config = ExAws.Config.new(:s3, region: get_region())
opts = [query_params: [{"response-content-disposition", "attachment; filename=#{file.filename}"}]]

{:ok, url} = ExAws.S3.presigned_url(config, :get, get_bucket(), file_path, opts)

If you redirect the user to this URL in your controller, it will automatically download and rename the file to file.filename.

Thanks for the tip!