2

I am trying to upload a PDF file to AWS S3 using multi part uploads. However, when I send the PUT request for uploading the part, I receive a SignatureDoesNotMatch error.

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

My Server Code (Node) is as below:

CREATE MultiPart Upload

const AWS = require('aws-sdk');

AWS.config.region = 'us-east-1';
const s3 = new AWS.S3({ apiVersion: '2006-03-01' });

const s3Params = {
      Bucket: 'bucket-name',
      Key: 'upload-location/filename.pdf',
    }

const createRequest = await s3.createMultipartUpload({
          ...s3Params
          ContentType: 'application/pdf'
        }).promise(); 

GET Signed URL

let getSignedUrlParams = {
      Bucket: 'bucket-name',
      Key: 'upload-location/filename.pdf',
      PartNumber: 1,
      UploadId: 'uploadId',
      Expires: 10 * 60
    }

const signedUrl = await s3.getSignedUrl('uploadPart',getSignedUrlParams);

And the Client code (in JS) is :

const response = await axios.put(signedUrl, chunkedFile, {headers: {'Content-Type':'application-pdf'}});

A few things to note:

  1. This code works when I allow all public access to the bucket.However, if all public access is blocked, the code does not work.
  2. With all public access blocked, I am still able to upload to the bucket with the same credentials using aws cli.
  3. I already have tried re-generating AWS Access Key ID and Secret Access Key and that didnt help.

Not able to figure out what the problem is. Any help would be appreciated.

PS: This is the first question I have posted here. So please forgive me if I havent posted it appropriately. Let me know if more details are required.

Rachit Anand
  • 616
  • 5
  • 16

3 Answers3

1

What worked for me was the version of the signature. While initializing S3, the signature version should also be mentioned.

const s3 = new AWS.S3({ apiVersion: '2006-03-01', signatureVersion: 'v4' });
Rachit Anand
  • 616
  • 5
  • 16
0

Try something like this,it worked for me.

var fileName = 'your.pdf';
var filePath = './' + fileName;
var fileKey = fileName;
var buffer = fs.readFileSync('./' + filePath);
// S3 Upload options
var bucket = 'loctest';

// Upload
var startTime = new Date();
var partNum = 0;
var partSize = 1024 * 1024 * 5; // Minimum 5MB per chunk (except the last part) http://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadComplete.html
var numPartsLeft = Math.ceil(buffer.length / partSize);
var maxUploadTries = 3;
var multiPartParams = {
    Bucket: bucket,
    Key: fileKey,
    ContentType: 'application/pdf'
};
var multipartMap = {
    Parts: []
};

function completeMultipartUpload(s3, doneParams) {
  s3.completeMultipartUpload(doneParams, function(err, data) {
    if (err) {
      console.log("An error occurred while completing the multipart upload");
      console.log(err);
    } else {
      var delta = (new Date() - startTime) / 1000;
      console.log('Completed upload in', delta, 'seconds');
      console.log('Final upload data:', data);
    }
  });
}

You will get error if the upload fails. We can help you to solve this if you print the results of

console.log(this.httpResponse)

and

console.log(this.request.httpRequest)
Richard Rublev
  • 7,718
  • 16
  • 77
  • 121
  • HI Richard, thanks for the response. However my issue is not with CompleteMultipartUpload, but with the PUT request sent to upload the part. The 'PUT' request itself throws the `SignatureDoesNotMatch` error. – Rachit Anand Apr 06 '20 at 15:58
0

Remove Content-Part header from the axios call.

const response = await axios.put(signedUrl, chunkedFile);

When adding only a part you're not actually uploading a complete file, so the content type is not application-pdf in your case.

This is different than doing a PUT for a complete object.

Radu Diță
  • 13,476
  • 2
  • 30
  • 34
  • Hi Radu. Thanks for your response. As far as in my experience, you need the header part in there, as you mention the Content Type while initiating the MPU. Adding the signature version along with the headers worked for me. – Rachit Anand Apr 09 '20 at 14:29