SignatureDoesNotMatch for multipart upload using signed URLs.
See original GitHub issueI have a setup where I start a multipart upload from a boto3 client, that also creates signed URLs for a javascript client to use.
I have tried a bunch of different configurations and parameters, but my PUT requests from the javascript client always are forbidden due to a SignatureDoesNotMatch error.
I found that the documentation is not really extensive on ClientMethods, on what and how is going to get signed when calling generate_presigned_url
, thus it’s very difficult to know what headers to send and how to make the PUT request from the javascript code.
As a side note: a similar setup is working in the project for traditional uploads with a single signed URL, using the put_object
ClientMethod.
Steps to reproduce The boto3 code:
@classmethod
def create_multipart_upload(cls, key):
return cls.s3_client.create_multipart_upload(
Bucket=config.AWS_S3_BUCKET_NAME,
Key=key,
# ACL='public-read', # I have tried all (or at least a lot of) the combinations of these commented parameters
# ContentType='binary/octet-stream'
)
[...]
@classmethod
def generate_multipart_presigned_urls(cls, key, upload_id, parts):
return [
{
'partNumber': p['partNumber'],
'url': cls.s3_client.generate_presigned_url(
ClientMethod='upload_part',
Params={
'Bucket': current_config.AWS_S3_BUCKET_NAME,
'Key': key,
'UploadId': upload_id,
'PartNumber': p['partNumber'],
# 'ContentLength': p['contentLength'], # I have also tried combinations of these parameters
# 'ContentMD5': p['md5']
# 'ContentType': 'binary/octet-stream', # These two are not acceptable here
# 'ACL': 'public-read'
},
HttpMethod='PUT',
ExpiresIn=60000,
)
}
for p in parts
]
The javascript code:
const uploadMultipartChunks = (chunks) => {
const promises = []
for (const c of chunks) {
// c.url comming from boto3 generate_presigned_url
promises.push(axios.put(c.url, c.blob, {
crossDomain: true,
headers: {
// Different combinations of headers were also tested here
// 'x-amz-acl': 'public-read',
// 'Content-Type': 'binary/octet-stream',
// 'Content-MD5': c.md5,
// 'Content-Length': chunkSize
}
}))
}
const resParts = await Promise.all(promises)
}
Issue Analytics
- State:
- Created 2 years ago
- Comments:5 (2 by maintainers)
Top GitHub Comments
Greetings! It looks like this issue hasn’t been active in longer than a week. We encourage you to check if this is still an issue in the latest release. Because it has been longer than a week since the last update on this, and in the absence of more information, we will be closing this issue soon. If you find that this is still a problem, please feel free to provide a comment or add an upvote to prevent automatic closure, or if the issue is already closed, please feel free to open a new one.
Hi @psancheztriller,
Thanks for letting us know! The signatures are calculated based on the parameters/client method provided here. If you turn on debug logs by adding
boto3.set_stream_logger('')
to your Python code, you’re able to see which auth type is being used.I realize you may have this somewhere in your code already, but just thought I’d throws this out there in case you weren’t aware: you’ll need to use the
complete_multipart_upload
api to re-assemble the parts once you’re finished using theupload_part
api. A brief example of this is shown here.I still think it would be helpful to see logs of the HTTP request/response from your JS code and snippets of any bucket policies (with sensitive information such as account numbers redacted) to further troubleshoot this.