angular - SignatureDoesNotMatch error when posting to AWS S3 presign url


Keywords:angular 


Question: 

Really struggling with this one, so any help would be great!

So I am attempting to upload a pdf file to Amazon S3 directly from the browser using presigned urls.

I generate the url on a server using the AWS Java SDK (code written in Kotlin), like this:

    val objectKey = StringBuilder().append("xxx").append("/").append("file1.pdf").toString()

    val expiration = java.util.Date()
    var msec = expiration.time
    msec += (1000 * 60).toLong() // Add 1 minute. This means that the url expires in 1 minute.
    expiration.time = msec

    String bucketName = "test"

    val responseHeaders = ResponseHeaderOverrides().withContentType("multipart/form-data")

    val generatePresignedUrlRequest = GeneratePresignedUrlRequest(bucketName, objectKey)
    generatePresignedUrlRequest.method = HttpMethod.POST
    generatePresignedUrlRequest.responseHeaders = responseHeaders
    generatePresignedUrlRequest.expiration = expiration

    return s3Client.generatePresignedUrl(generatePresignedUrlRequest)

This url is then returned to the browser code, which is using Angular. I then used the following typescript code to upload the file directly:

returnPresignUrl() {
   return this.http.get(this.attachmentUploadUrl, this.httpOptions);

}

   uploadFiletoS3(file, filetype) {
       let presignURL;
       const data = file;
       const fileHeaders = {
           headers: new HttpHeaders({
               'Content-Type': 'multipart/form-data',
           })
       };
       this.returnPresignUrl().subscribe(url => {
           presignURL = url;
           this.http.post(presignURL, data, 
fileHeaders).subscribe((res) => {
               console.log('File uploaded', res);
           }, (error) => { console.log('Error uploading File', error); 
});
       }, (error) => { console.log('Error getting a preasign URL: ', 
error); });
   }

But I get the following error response:

<Code>SignatureDoesNotMatch</Code>
<Message>
    The request signature we calculated does not match the signature you 
provided. Check your key and signing method.
</Message>

Any ideas?

I am specifying the content type header in the presign url and then also setting it in the post request to the url, so I can't see how there would be a header mismatch (an error that seems to cause the problem that I am seeing).

Is there anything special about post requests? Is the content type correct for uploading pdf files to S3?

Any insight would be awesome, thanks!


1 Answer: 

Use: generatePresignedUrlRequest.setContentType("application/octet-stream");

instead of: multipart/form-data.

Here my method for generating the PreSigned URL:

public GeneratePresignedUrlRequest getGeneratePresignedUrlRequest(String tempBucketName,String objectKey){
    Date expirationTime = getExpirationTime();
    GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(tempBucketName, objectKey);
    generatePresignedUrlRequest.setMethod(HttpMethod.PUT);
    generatePresignedUrlRequest.setExpiration(expirationTime);
    generatePresignedUrlRequest.setContentType("application/octet-stream");
    return generatePresignedUrlRequest;
}

When you make call put call to upload the file you should use the same Content-Type.