AWS Multipart Upload SignatureDoesNotMatch

2.4k Views Asked by At

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.

3

There are 3 best solutions below

0
On BEST ANSWER

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' });
1
On

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)
1
On

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.