I want to create a presigned url for the objects in my bucket. I use the following python code:
client = boto3.client(
's3',
aws_access_key_id=os.environ['AWS_ACCESS_KEY'],
aws_secret_access_key=os.environ['AWS_SECRETS_KEY'],
config=botocore.client.Config(signature_version='s3v4'),
region_name='eu-central-1'
)
url = client.generate_presigned_url(
ClientMethod='get_object',
ExpiresIn=60,
Params={
'Bucket': MYBUCKET,
'Key': MYKEY
})
I then send the generated URL to my frontend. On the client I will create an a tag with the generated link and use the click() method on it. This worked fine in other projects but here I only get the error:
The request signature we calculated does not match the signature you provided. Check your key and signing method.
Which is strange. The user should have all the necessary rights. Because listing all the files in my bucket works fine.
Can someone point me in the right direction why this isn't working?
EDIT
I'm using next.js on the frontend if this is of help.
Had the exact same problem. Studied the AWS docs and wrote the (signature v4) procedure myself. The below is based on
https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
and works perfectly.
ENCODING = 'utf8'
SEVEN_DAYS = 604800
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def sign(key, msg):
return hmac.new(key, msg.encode(ENCODING), hashlib.sha256).digest()
def get_signature_key(key, dateStamp, regionName, serviceName):
kDate = sign(('AWS4' + key).encode(ENCODING), dateStamp)
kRegion = sign(kDate, regionName)
kService = sign(kRegion, serviceName)
kSigning = sign(kService, 'aws4_request')
return kSigning
def generate_presigned_s3_get(bucket, object_key, region, expires_in, access_key, secret_key):
METHOD = 'GET'
SERVICE = 's3'
host = bucket + '.s3.' + region + '.amazonaws.com'
endpoint = 'https://' + host
t = datetime.datetime.utcnow()
amz_date = t.strftime('%Y%m%dT%H%M%SZ')
datestamp = t.strftime('%Y%m%d')
canonical_uri = '/' + object_key
canonical_headers = 'host:' + host + '\n'
signed_headers = 'host'
algorithm = 'AWS4-HMAC-SHA256'
credential_scope = datestamp + '/' + region + '/' + SERVICE + '/' + 'aws4_request'
canonical_querystring = '?X-Amz-Algorithm=AWS4-HMAC-SHA256'
canonical_querystring += '&X-Amz-Credential=' + urllib.parse.quote_plus(access_key + '/' + credential_scope)
canonical_querystring += '&X-Amz-Date=' + amz_date
canonical_querystring += '&X-Amz-Expires=' + str(expires_in)
canonical_querystring += '&X-Amz-SignedHeaders=' + signed_headers
canonical_request = METHOD + '\n' + canonical_uri + '\n' + canonical_querystring[1:] + '\n' + canonical_headers + '\n' + signed_headers + '\nUNSIGNED-PAYLOAD'
string_to_sign = algorithm + '\n' + amz_date + '\n' + credential_scope + '\n' + hashlib.sha256(canonical_request.encode(ENCODING)).hexdigest()
signing_key = get_signature_key(secret_key, datestamp, region, SERVICE)
signature = hmac.new(signing_key, (string_to_sign).encode("utf-8"), hashlib.sha256).hexdigest()
canonical_querystring += '&X-Amz-Signature=' + signature
url = endpoint + canonical_uri + canonical_querystring
logger.info('presigned url: %s' % url)
return url
I've also reported this issue to boto3 peeps: https://github.com/boto/boto3/issues/1644
The problem was the version of boto3.
I tried the latest version (boto3 1.7.14) which yielded above mentioned error.
Works exactly like I want it to with version 1.6.6.
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