How do I upload a file to a pre-signed URL in AWS using Node.js and Axios?

10,677

The issue here is, axios for some reason adding a default Content-Type: application/json header. thats the reason why the signature is failing to match. I am not sure how to remove the header.

But following works for me where I am including the content-type during the signature generation. Also I am including the same header when using it.

(async () => {
  try {
    const presignedS3Url = s3.getSignedUrl('putObject', {
      Bucket: 'bucket-name',
      Key: 'car.jpg',
      ContentType: 'application/octet-stream'
    });
    const file = await readFile('./car.jpg');

    const axiosResponse = await axios.put(presignedS3Url, {
      data: file,

    }, {
      headers: {
        'Content-Type': 'application/octet-stream'
      }
    });
    console.info(axiosResponse)
  } catch (e) {
    console.error(e)
  }
})();
Share:
10,677
misterioss
Author by

misterioss

Updated on July 31, 2022

Comments

  • misterioss
    misterioss almost 2 years

    I have next scenario:

    1. Generate a signed URL for file upload by AWS-SDK
    2. Try to upload a local file using Axios (or request) npm package

    But every time I have an error:

    Status: 403 statusText: Forbidden

    <?xml version="1.0" encoding="UTF-8"?>
    <Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><AWSAccessKeyId>FakeKeyId</AWSAccessKeyId><StringToSign>PUT
    
    application/json;charset=utf-8
    1577742550
    /test-bucket-super/xxx/test.mp3</StringToSign><SignatureProvided>DAAOZ0/VkMNEMMlGkRUsSuRO3J4=</SignatureProvided><StringToSignBytes>50 55 54 0a 0a 61 70 70 6c 69 63 61 74 69 6f 6e 2f 6a 73 6f 6e 3b 63 68 61 72 73 65 74 3d 75 74 66 2d 38 0a 31 35 37 37 37 34 32 35 35 30 0a 2f 74 65 73 74 2d 62 75 63 6b 65 74 2d 73 75 70 65 72 2f 78 78 78 2f 74 65 73 74 2e 6d 70 33</StringToSignBytes><RequestId>CBD3F1D0D02EA874</RequestId><HostId>LPu+RQ8otcljI1Wt5FiZm+UmTFNiCX+2HyGtN0kTAugLiT21M55DtbzQdF/s7qOCSaZvzTp4kw4=</HostId></Error>
    
    const axios = require('axios');
    const AWS = require('aws-sdk')
    
    const s3 = new AWS.S3({
        accessKeyId: 'FakeKeyId',
        secretAccessKey: 'xxxxxxxxxxxxxxxxxxxxxxxx',
        region: 'eu-west-1'
    });
    
    const fs = require('fs');
    const readFile = require('util').promisify(fs.readFile);
    
    (async () => {
        try {
            const presignedS3Url = s3.getSignedUrl('putObject', {
                Bucket: 'test-bucket-super',
                Key: 'xxx/test.mp3'
            });
            const file = await readFile('./SampleAudio_0.4mb.mp3');
    
            const axiosResponse = await axios.put(presignedS3Url, {
                data: file,
            });
            console.info(axiosResponse)
        } catch (e) {
            console.error(e)
        }
    })();
    
    

    But I managed to upload the file via cURL

    curl -X PUT -T ~/Downloads/SampleAudio_0.4mb.mp3 'https://test-bucket-super.s3.eu-west-1.amazonaws.com/xxx/test.mp3?AWSAccessKeyId=FakeKeyId&Expires=1577741900&Signature=9kPiC%2B85SEFp6g5C3nwEWe4TueU%3D' -v