1

My Front-end is a Nativescript-Vue app. Backend is Rails. I'm getting a presigned url from the rrails server and using that to send a put request on the client side to do an image upload. I've generated a presigned url on rails like so, following this:

def create_presigned_url
  filename = "#{self.id}.jpg"

  Aws.config[:credentials]=Aws::Credentials.new(
    "secret_id",
    "secret_key")
  s3 = Aws::S3::Resource.new(region: 'ap-southeast-1')

  bucket = 'bucket_name'
  obj = s3.bucket(bucket).object(filename)
  self.presigned_url = obj.presigned_url(:put, { acl: 'public-read' })
  self.update_column(:image_url, obj.public_url)
end

Long story short, the above code generates a presigned url and I use it to do a put request on the client-side using the NativeScript-background-http plugin:

var session = bghttp.session("image-upload");

UploadFile(session, file, url) {
    var request = {
      url: url,
      method: "PUT",
      headers: {
          "Content-Type": "application/octet-stream"
      },
      description: `Uploading ${file.substr(file.lastIndexOf("/") + 1)}` 
    };

    var task = session.uploadFile(file, request);
}

The image upload works fine, it shows:

LOG from device Nexus 6P: 'currentBytes: 4096'
LOG from device Nexus 6P: 'totalBytes: 622121'
LOG from device Nexus 6P: 'eventName: progress'
LOG from device Nexus 6P: 'currentBytes: 323584'
LOG from device Nexus 6P: 'totalBytes: 622121'
LOG from device Nexus 6P: 'eventName: progress'
LOG from device Nexus 6P: 'currentBytes: 606208'
LOG from device Nexus 6P: 'eventName: progress'
LOG from device Nexus 6P: 'totalBytes: 622121'
LOG from device Nexus 6P: 'currentBytes: 622121'
LOG from device Nexus 6P: 'totalBytes: 622121'
LOG from device Nexus 6P: 'eventName: progress'
LOG from device Nexus 6P: 'eventName: error'
LOG from device Nexus 6P: 'eventName: 403'
LOG from device Nexus 6P: 'eventName: {}'

There's a 403 error, the response is:

<?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>
...

I've googled the error and seen that all the responses on SO are about having incorrect AWS keys however, I have made sure I have the correct AWS credentials on rails. I suspect it may have something to do with the content type whilst generating the presigned url but I'm not sure. My bucket permissions seem to be correct but I could've missed something there. I've set the policy and CORS.

This is the bucket policy:

{
    "Version": "2012-10-17",
    "Id": "my-policy-id",
    "Statement": [
        {
            "Sid": "my-sid",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::my-id:user/my-user"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::my-bucket/*"
        }
    ]
}

This is the CORS:

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

and my IAM user has the necessary policy as well.

Any insight would be appreciated.

EDIT: I've even deleted the bucket policy and granted all public access to the bucket however I'm still seeing the 403 error. The error is the signature one.

Ayudh
  • 1,673
  • 1
  • 22
  • 55

1 Answers1

1

I had to change self.presigned_url = obj.presigned_url(:put, { acl: 'public-read' }) to self.presigned_url = obj.presigned_url(:put, expires_in: 10*60, content_type: 'application/octet-stream')

and the bucket ACL for Everyone to Public List, Private Write. The bucket Policy to

{
    "Version": "2012-10-17",
    "Id": "policy_id",
    "Statement": [
        {
            "Sid": "my_statement_id",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::user_id:user/iam_user"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::my_bucket/*"
        },
        {
            "Sid": "PublicRead",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion"
            ],
            "Resource": "arn:aws:s3:::my_bucket/*"
        }
    ]
}
Ayudh
  • 1,673
  • 1
  • 22
  • 55