0
votes

I'm trying to get a pre-signed URL from s3.getSignedUrl, so I could directly upload a file/image from the client react side. I get a URL but whenever I open that link or if I try to make put a request on that URL from the client, I always get a 403 forbidden error. I'm not doing this in serverless

// code to get a presigned url
const s3 = new AWS.S3({
  accessKeyId: keys.ACCESS_KEY,
  secretAccessKey: keys.SECRET_KEY,
});

const router = express.Router();

// this method is returning a url, configured with the Key, we shared
router.get(
  '/api/image-upload/get-url',
  requireAuth,
  async (req: Request, res: Response) => {
    // we want our key to be like this -- myUserId/12122113.jpeg -- where filename will be used as a random unique string
    const key = `${req.currentUser!.id}/${uuid()}.jpeg`;

    s3.getSignedUrl(
      'putObject',
      {
        Bucket: 'my-first-s3-bucket-1234567',
        ContentType: 'image/jpeg',
        Key: key,
      },
      (err, url) => res.send({ key, url, err })
    );
  }
);

I get the object back having Key and Url property and if I open that URL or if I try to make a PUT request from the client-side, I get 403 Forbidden Error

// Error
<Error>
<link type="text/css" rel="stylesheet" id="dark-mode-custom-link"/>
<link type="text/css" rel="stylesheet" id="dark-mode-general-link"/>
<style lang="en" type="text/css" id="dark-mode-custom-style"/>
<style lang="en" type="text/css" id="dark-mode-native-style"/>
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
<AWSAccessKeyId>AKIA2YLSQ26Z6T3PRLSR</AWSAccessKeyId>
<StringToSign>GET 1616261901 /my-first-s3-bucket-12345/60559b4dc123830023031184/f852ca00-89a0-11eb-a3dc-07c38e9b7626.jpeg</StringToSign>
<SignatureProvided>TK0TFR+I79t8PPbtRW37GYaOo5I=</SignatureProvided>
<StringToSignBytes>47 45 54 0a 0a 0a 31 36 31 36 32 36 31 39 30 31 0a 2f 6d 79 2d 66 69 72 73 74 2d 73 33 2d 62 75 63 6b 65 74 2d 31 32 33 34 35 2f 36 30 35 35 39 62 34 64 63 31 32 33 38 33 30 30 32 33 30 33 31 31 38 34 2f 66 38 35 32 63 61 30 30 2d 38 39 61 30 2d 31 31 65 62 2d 61 33 64 63 2d 30 37 63 33 38 65 39 62 37 36 32 36 2e 6a 70 65 67</StringToSignBytes>
<RequestId>56RQCDS1X5GMF4JH</RequestId>
<HostId>LTA1+vXnwzGcPo70GmuKg0J7QDzW4+t+Ai9mgVqcerRKDbXkHBOnqU/7ZTvMLpyDf1CLZMYwSMY=</HostId>
</Error>

Please have a look at my s3 bucket policies and cors

// S3 Bucket Policies 
{
    "Version": "2012-10-17",
    "Id": "Policy1616259705897",
    "Statement": [
        {
            "Sid": "Stmt1616259703206",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:GetObjectAcl"
            ],
            "Resource": "arn:aws:s3:::my-first-s3-bucket-1234567/*"
        }
    ]
}

 // S3 CORS [
     {
         "AllowedHeaders": [
             "*"
         ],
         "AllowedMethods": [
             "GET"
         ],
         "AllowedOrigins": [
             "*"
         ],
         "ExposeHeaders": [],
         "MaxAgeSeconds": 3000
     },
     {
         "AllowedHeaders": [
             "*"
         ],
         "AllowedMethods": [
             "PUT",
             "POST",
             "DELETE"
         ],
         "AllowedOrigins": [
             "https://ticketing.dev"
         ],
         "ExposeHeaders": [
             "x-amz-server-side-encryption",
             "x-amz-request-id",
             "x-amz-id-2",
             "ETag"
         ],
         "MaxAgeSeconds": 3000
     } ]

I'm unable to resolve this issue. Please bear with me, I'm not a good questioner. Thanks

1
Can you show your client-side upload code?jellycsc

1 Answers

0
votes

After a lot of debugging, I had to give my IAM user, AmazonS3FullAccess to make it work. Maybe it would need some specific permission to make a put request to s3 presigned url