Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error uploading file to S3 with presigned url using JQuery

We are trying to upload a file to S3 using jQuery ajax & a presigned url. We generate the presigned url on the server. Currently we are trying to use FormData to upload the file.

          var uploadData = new FormData(),
            files = $(this.input).prop('files'),
            file = files[0];

          uploadData.append('file', file);

          $.ajax({
            url: '{presigned url string}',
            type: 'PUT',
            data: uploadData,
            cache: false,
            processData: false,
            contentType: false,
            success: function(response) {
              console.log('S3 upload success!');
            },
            error: function(response) {
              console.log('Error with S3 upload: ' + response.statusText);
            }
          });

This returns a SignatureDoesNotMatch error from AWS:

<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we 
calculated does not match the signature you provided. Check your key and 
signing method.</Message><StringToSignBytes>50 55 54 0a 0a 6d 75 6c 74 69 70 61 72 74 2f 66 6f 72 6d 2d 64 61 74 61 3b 20 62 6f 75 6e 64 61 72 79 3d 2d 2d 2d 2d 57 65 62 4b 69 74 46 6f 72 6d 42 6f 75 6e 64 61 72 79 67 57 6f 4a 73 42 56 79 41 4c 57 71 51 6b 73 69 0a 31 34 30 39 37 37 37 32 39 33 0a 2f 64 69 2d 6b 79 72 73 74 65 6e 2d 64 65 61 6c 73 2f 76 4e 79 4b 4e 55 4c 37 51 68 4f 30 45 4b 38 52 58 44 70 32 59 77 25 32 46 63 35 37 65 64 37 62 39 2d 64 63 61 62 2d 34 63 30 62 2d 62 36 63 30 2d 36 31 66 30 36 62 32 30 37 34 66 31 2d 74 65 73 74 2e 74 78 74</StringToSignBytes>
<RequestId>ED7C581570F547DB</RequestId><HostId>ZT6LsFYCbo1L0gYNcUwtdCWF6SNnyuUyKiL60ntJEZugx3cnDN/yH5KBjgEiBv5c</HostId><SignatureProvided>N2d7oNMVHvI6yxAXujNy8O5cF24=</SignatureProvided>
<StringToSign>PUT

multipart/form-data; boundary=----WebKitFormBoundarygWoJsBVyALWqQksi
1409777293
/test-bucket/vNyKNUL7QhO0EK8RXDp2Yw%2Fc57ed7b9-dcab-4c0b-b6c0-61f06b2074f1-test.txt</StringToSign><AWSAccessKeyId>FAKEACCESSKEY</AWSAccessKeyId></Error>  

I know that the presigned url works because I can upload the file correctly via CURL:

curl -v --upload-file {filename} {presigned url}
like image 832
kyrsten Avatar asked Sep 02 '14 20:09

kyrsten


People also ask

How do I upload a Presigned URL?

Generating a presigned URL for uploading objects. You can generate a presigned URL programmatically using the AWS SDKs for . NET, Java, Ruby, JavaScript, PHP, and Python . You can use the AWS SDK to generate a presigned URL that you or anyone that you give the URL to can use to upload an object to Amazon S3.

How does Presigned URL work S3?

A user who does not have AWS credentials or permission to access an S3 object can be granted temporary access by using a presigned URL. A presigned URL is generated by an AWS user who has access to the object. The generated URL is then given to the unauthorized user.

How long is S3 Presigned URL valid for?

In the Amazon S3 console, the maximum expiration time for a presigned URL is 12 hours from the time of creation.

What is signed URL in S3?

S3 pre-signed URLs are a form of an S3 URL that temporarily grants restricted access to a single S3 object to perform a single operation — either PUT or GET — for a predefined time limit. To break it down: It is secure — the URL is signed using an AWS access key.


1 Answers

We found the issue ourselves. Here is the code we were using to generate the pre-signed url:

val dt: DateTime = new DateTime()
val expiration = DateTime.now.plusMillis(timeout.toInt)
val presignedUrlRequest: GeneratePresignedUrlRequest =
  new GeneratePresignedUrlRequest(awsBucket, key, HttpMethod.PUT)
presignedUrlRequest.setExpiration(expiration.toDate())
// WE ADDED THIS LINE
presignedUrlRequest.setContentType("multipart/form-data")

s3client.generatePresignedUrl(presignedUrlRequest).toString()

We had to set the content type in the presignedUrlRequest as well as add
headers: {'Content-Type': 'multipart/form-data'} to our ajax call.

The way we were generating the url at first worked with CURL since we weren't setting the content-type in the presignedUrlRequest and curl wasn't setting a content-type.

like image 192
kyrsten Avatar answered Oct 12 '22 22:10

kyrsten