I'm trying to generate a pre-signed URL then upload a file to S3 through a browser. My server-side code looks like this, and it generates the URL:
let s3 = new aws.S3({ // for dev purposes accessKeyId: 'MY-ACCESS-KEY-ID', secretAccessKey: 'MY-SECRET-ACCESS-KEY' }); let params = { Bucket: 'reqlist-user-storage', Key: req.body.fileName, Expires: 60, ContentType: req.body.fileType, ACL: 'public-read' }; s3.getSignedUrl('putObject', params, (err, url) => { if (err) return console.log(err); res.json({ url: url }); });
This part seems to work fine. I can see the URL if I log it and it's passing it to the front-end. Then on the front end, I'm trying to upload the file with axios and the signed URL:
.then(res => { var options = { headers: { 'Content-Type': fileType } }; return axios.put(res.data.url, fileFromFileInput, options); }).then(res => { console.log(res); }).catch(err => { console.log(err); }); }
With that, I get the 403 Forbidden error. If I follow the link, there's some XML with more info:
<Error> <Code>SignatureDoesNotMatch</Code> <Message> The request signature we calculated does not match the signature you provided. Check your key and signing method. </Message> ...etc
If you're trying to host a static website using Amazon S3, but you're getting an Access Denied error, check the following requirements: Objects in the bucket must be publicly accessible. S3 bucket policy must allow access to the s3:GetObject action. The AWS account that owns the bucket must also own the object.
S3 pre-signed URLs are a form of an S3 URL that temporarily grants restricted access to a single S3 object to perform a single operation — either PUT or GET — for a predefined time limit. To break it down: It is secure — the URL is signed using an AWS access key.
Sign in to the AWS Management Console and open the Amazon S3 console at https://console.aws.amazon.com/s3/ . In the Buckets list, choose the name of the bucket that contains the object that you want a presigned URL for. In the Objects list, select the object that you want to create a presigned URL for.
Your request needs to match the signature, exactly. One apparent problem is that you are not actually including the canned ACL in the request, even though you included it in the signature. Change to this:
var options = { headers: { 'Content-Type': fileType, 'x-amz-acl': 'public-read' } };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With