wazzaday
wazzaday

Reputation: 9664

S3 Upload image with pre-signed url from browser

I am trying to upload data to an s3 bucket from the browser. I have generated a pre-signed url but I get a 403 forbidden response.

My server code is

const s3 = new AWS.S3({
  accessKeyId: settings.resourceBucketKey,
  secretAccessKey: settings.resourceBucketSecret,
  region: 'eu-west-1'
})

const params = {
  Bucket: 'my-bucket',
  Key: 'photo.png',
  ContentType: 'image/png',
  ACL: 'authenticated-read',
}

const url = s3.getSignedUrl('putObject', params)

console.log(url)

My client code is (using the generated url)

const input = $('#myinput')

      input.on('change', (res) => {
        var theFormFile = $('#myinput').get()[0].files[0];

        $.ajax({
          url: url,
          type: 'PUT',
          contentType: 'image/png',
          processData: false,
          data: theFormFile,
        }).success(function(){
          alert('success')
        })
      }, false)

I have set cors on on the bucket to:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

But I still get 403 forbidden on the response. The image I am trying to upload is call 'photo.png'. Am I missing something here?

Upvotes: 5

Views: 8705

Answers (2)

Liad Livnat
Liad Livnat

Reputation: 7475

Full implementation of getting signed url from browser - enjoy!

<body>
  <img height="200" width="200">
  <script>

    var mimes = {
        'jpeg': 'data:image/jpeg;base64,'
    };

      AWS.config.update({
          signatureVersion: 'v4',
          region: 'us-east-1',
          accessKeyId: '',
          secretAccessKey: ''
      });

      var bucket = new AWS.S3({params: {Bucket: 'xxxx'}});

      function encode(data)
      {
          var str = data.reduce(function(a,b){ return a+String.fromCharCode(b) },'');
          return btoa(str).replace(/.{76}(?=.)/g,'$&\n');
      }

      function getUrlByFileName(fileName,mimeType) {
          return new Promise(
              function (resolve, reject) {
                  bucket.getObject({Key: fileName}, function (err, file) {
                      var result =  mimeType + encode(file.Body);
                      resolve(result)
                  });
              }
          );
      }

      function openInNewTab(url) {
          var redirectWindow = window.open(url, '_blank');
          redirectWindow.location;
      }

      getUrlByFileName('sprites.png', mimes.jpeg).then(function(data) {
          //openInNewTab(data);
          document.querySelector('img').src = data;
      });

  </script>
</body>

Upvotes: -5

jzonthemtn
jzonthemtn

Reputation: 3404

The creator (you) of the pre-signed URL must have permissions to be able to access the S3 bucket to upload a file. This is more eloquently described in the S3 documentation:

A pre-signed URL gives you access to the object identified in the URL, provided that the creator of the pre-signed URL has permissions to access that object. That is, if you receive a pre-signed URL to upload an object, you can upload the object only if the creator of the pre-signed URL has the necessary permissions to upload that object.

Make sure the IAM user that is creating the pre-signed URL has the necessary permissions.

Upvotes: 5

Related Questions