title: Image upload to s3 using presigned url with ReactJs/NodeJS throws 403 error SignatureDoesNotMatch
body: <p>I have successfully integrated image upload to S3 using presigned url in <strong>App1</strong>.<br />
  I tried to do the same thing in an <strong>App 2</strong>, but I keep getting the same error:</p>
  <blockquote>
  <p>403 SignatureDoesNotMatch</p>
  </blockquote>
  <hr />
  <p><strong>FRONTEND:</strong></p>
  <pre><code>import React from &quot;react&quot;;
  import { uploadAdImageToS3BucketAndReturnImageUrl } from &quot;../../../api/calls/data/ads/ads-configuration&quot;;
  export default function UploadImageTutorial1() {
    const onSelectFile = async (event) =&gt; {
      const file = event.target.files[0];
  
      const { type, name } = file;
      // This throws an error
      await uploadAdImageToS3BucketAndReturnImageUrl(file, type);
    };
    return (
      &lt;div&gt;
        &lt;input type=&quot;file&quot; accept=&quot;image/*&quot; onChange={onSelectFile} /&gt;;
      &lt;/div&gt;
    );
  }
  </code></pre>
  <blockquote>
  <p>api/calls.js</p>
  </blockquote>
  <pre><code>export const uploadAdImageToS3BucketAndReturnImageUrl = async (
    imageFile,
    typeFile
  ) =&gt; {
    try {
      const [axios, cancel] = useAxios();
      const { data: uploadConfig } = await axios.get(
        &quot;/ads/get_image_presigned_url&quot;
      );
      const saved_image_url = await uploadImageFileToCloud(
        uploadConfig,
        imageFile,
        typeFile
      );
  
      return saved_image_url;
    } catch (e) {}
  };
  const uploadImageFileToCloud = async (uploadConfig, imageFile, typeFile) =&gt; {
    const [axios, cancel] = useAxios();
    try {
      // This throws 400 error
      await axios.put(uploadConfig.url, imageFile, {
        headers: {
          &quot;Content-Type&quot;: typeFile,
          &quot;x-amz-acl&quot;: &quot;public-read&quot;,
        },
        transformRequest: (data, headers) =&gt; {
          delete headers.common[&quot;Authorization&quot;];
          return data;
        },
      });
    } catch (error) {
      console.log(&quot; error&quot;, error);
    }
  };
  </code></pre>
  <hr />
  <p><strong>BACKEND:</strong></p>
  <blockquote>
  <p>s3-config.js</p>
  </blockquote>
  <pre><code>// Load the SDK for JavaScript
  const { config } = require(&quot;dotenv&quot;);
  config();
  
  var AWS = require(&quot;aws-sdk&quot;);
  const REGION = &quot;xxxxxxxxx&quot;; //e.g. &quot;us-east-1&quot;
  AWS.config.update({ region: REGION });
  const { AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_BUCKET_NAME } =
    process.env;
  
  
  const s3 = new AWS.S3({
    accessKeyId: AWS_ACCESS_KEY_ID,
    secretAccessKey: AWS_SECRET_ACCESS_KEY,
    signatureVersion: &quot;v4&quot;,
  });
  
  var getImageSignedUrl = async function (key) {
    return new Promise((resolve, reject) =&gt; {
      s3.getSignedUrl(
        &quot;putObject&quot;,
        {
          Bucket: AWS_BUCKET_NAME,
          Key: key,
          ContentType: &quot;image/*&quot;,
          ACL: &quot;public-read&quot;,
          Expires: 300,
        },
        (err, url) =&gt; {
          if (err) {
            reject(err);
          } else {
            resolve(url);
          }
        }
      );
    });
  };
  
  exports.getImageSignedUrl = getImageSignedUrl;
  </code></pre>
  <blockquote>
  <p>routes/upload.js</p>
  </blockquote>
  <pre><code>// @route  POST api/ads/get_image_presigned_url
  // @desc   Get image presigned url
  // @access Private
  
  router.get(&quot;/get_image_presigned_url&quot;, (req, res) =&gt; {
    const key = `images/ad_${Date.now()}.jpeg`;
    s3_config
      .getImageSignedUrl(key)
      .then((url) =&gt; {
        res.status(200).send({ key, url });
      })
      .catch((error) =&gt; {
        res.status(500).send({
          message: &quot;There was an error generating pre-signed url.&quot;,
        });
      });
  });
  </code></pre>
  <hr />
  <p>When I try to upload an image using the code above, in the frontend, this error gets logged:</p>
  <blockquote>
  <p>PUT
  <a href="https://bucket-name.s3.region.amazonaws.com/images/file_name.jpeg?Content-Type=image%2F%2A&amp;X-Amz-Algorithm=XXX-XXX-SHA256&amp;X-Amz-Credential=XXXXXXX%2F20220526%2Feu-west-3%2Fs3%2Faws4_request&amp;X-Amz-Date=20220526T121600Z&amp;X-Amz-Expires=300&amp;X-Amz-Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&amp;X-Amz-SignedHeaders=host%3Bx-amz-acl&amp;x-amz-acl=public-read" rel="nofollow noreferrer">https://bucket-name.s3.region.amazonaws.com/images/file_name.jpeg?Content-Type=image%2F%2A&amp;X-Amz-Algorithm=XXX-XXX-SHA256&amp;X-Amz-Credential=XXXXXXX%2F20220526%2Feu-west-3%2Fs3%2Faws4_request&amp;X-Amz-Date=20220526T121600Z&amp;X-Amz-Expires=300&amp;X-Amz-Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&amp;X-Amz-SignedHeaders=host%3Bx-amz-acl&amp;x-amz-acl=public-read</a>
  400 (Bad Request)</p>
  </blockquote>
  <p>When I click on it, this opens in a new page:</p>
  <pre><code>&lt;Error&gt;
    &lt;Code&gt;SignatureDoesNotMatch&lt;/Code&gt;
    &lt;Message&gt;
      The request signature we calculated does not match the signature you
      provided. Check your key and signing method.
    &lt;/Message&gt;
    &lt;AWSAccessKeyId&gt;XXXXXXXXXXXXXXXXXXXXXx&lt;/AWSAccessKeyId&gt;
    &lt;StringToSign&gt;
      AWS4-XXXX-XXXX 20220526T121600Z 20220526/region/s3/aws4_request
      d058c00da90b745bd2xxxxxxxxxxxxxxxxd68b3c537ff
    &lt;/StringToSign&gt;
    &lt;SignatureProvided&gt;
      9b372d73xxxxxxxxxxxxxxxxxxxxxx069c90ab7e24193990f1bcd39a0
    &lt;/SignatureProvided&gt;
    &lt;StringToSignBytes&gt;
      xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 36
      54 31 32 31 36 30 30 5a 0a 32 30 32 32 30 35 32 36 2f 65 75 2d 77 65 73 74
      2d 33 2f 73 33 2f 61 77 73 34 5f 72 65 71 75 65 73 74 0a 64 30 35 38 63 30
      30 64 61 39 30 62 37 34 35 62 64 32 66 66 37 62 35 33 31 39 62 38 61 37 32
      33 34 36 37 35 33 65 64 63 31 38 62 63 62 36 38 37 31 65 62 63 39 64 36 38
      62 33 63 35 33 37 66 66
    &lt;/StringToSignBytes&gt;
    &lt;CanonicalRequest&gt;
      GET /images/image_name.jpeg
      Content-Type=image%2F%2A&amp;X-Amz-Algorithm=AWS4-XXXX-XXXXX&amp;X-Amz-Credential=XXXXXXXXXXXX%2F20220526%2Feu-west-3%2Fs3%2Faws4_request&amp;X-Amz-Date=20220526T121600Z&amp;X-Amz-Expires=300&amp;X-Amz-SignedHeaders=host%3Bx-amz-acl&amp;x-amz-acl=public-read
      host:bucket-name.s3.region.amazonaws.com x-amz-acl:public-read
      host;x-amz-acl UNSIGNED-PAYLOAD
    &lt;/CanonicalRequest&gt;
    &lt;CanonicalRequestBytes&gt;
      xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 30
      32 31 38 2e 6a 70 65 67 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3d 69 6d 61
      67 65 25 32 46 25 32 41 26 58 2d 41 6d 7a 2d 41 6c 67 6f 72 69 74 68 6d 3d
      41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 26 58 2d 41 6d 7a 2d 43 72
      65 64 65 6e 74 69 61 6c 3d 41 4b 49 41 52 5a 41 52 52 50 50 49 42 4d 56 45
      57 4b 55 57 25 32 46 32 30 32 32 30 35 32 36 25 32 46 65 75 2d 77 65 73 74
      2d 33 25 32 46 73 33 25 32 46 61 77 73 34 5f 72 65 71 75 65 73 74 26 58 2d
      41 6d 7a 2d 44 61 74 65 3d 32 30 32 32 30 35 32 36 54 31 32 31 36 30 30 5a
      26 58 2d 41 6d 7a 2d 45 78 70 69 72 65 73 3d 33 30 30 26 58 2d 41 6d 7a 2d
      53 69 67 6e 65 64 48 65 61 64 65 72 73 3d 68 6f 73 74 25 33 42 78 2d 61 6d
      7a 2d 61 63 6c 26 78 2d 61 6d 7a 2d 61 63 6c 3d 70 75 62 6c 69 63 2d 72 65
      61 64 0a 68 6f 73 74 3a 6c 6f 64 65 65 70 2d 73 74 6f 72 61 67 65 2d 33 2e
      73 33 2e 65 75 2d 77 65 73 74 2d 33 2e 61 6d 61 7a 6f 6e 61 77 73 2e 63 6f
      6d 0a 78 2d 61 6d 7a 2d 61 63 6c 3a 70 75 62 6c 69 63 2d 72 65 61 64 0a 0a
      68 6f 73 74 3b 78 2d 61 6d 7a 2d 61 63 6c 0a 55 4e 53 49 47 4e 45 44 2d 50
      41 59 4c 4f 41 44
    &lt;/CanonicalRequestBytes&gt;
    &lt;RequestId&gt;XXXXXXXXXXX&lt;/RequestId&gt;
    &lt;HostId&gt;
      q1cQMi/q0jrkk3SeLd3F8/v/mx62XXXXXXXXXXXXXQbVhCdZCDBNfnluTruGLnkhM=
    &lt;/HostId&gt;
  &lt;/Error&gt;;
  </code></pre>
  <p>What’s weird is that SignatureDoesNotMatch is 403 error on their <a href="https://www.google.com/url?q=https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html&amp;sa=D&amp;source=docs&amp;ust=1653580746660730&amp;usg=AOvVaw2-MhxVZ8Bhis4xrHEZt3EV" rel="nofollow noreferrer">documentation</a>.</p>
  <p>I know others have faced the same issue but it seems to be triggered by different causes and I still haven't found what's causing this.<br />
  <a href="https://stackoverflow.com/questions/20709711/amazon-s3-signature-does-not-match-aws-sdk-java">Here</a>, in one answer, this is mentioned:</p>
  <blockquote>
  <p>When making a signed request to S3, AWS checks to make sure that the
  signature exactly matches the HTTP Header information the browser
  sent.</p>
  </blockquote>
  <p>This may be what's causing the issue. But, I don't know what exactly.</p>