Closed chasen-bettinger closed 6 years ago
I'm not sure what language that is? CoffeeScript?
Can you please post a better reproduction with actual values (including the structure of aws_credentials
, although just use dummy variables for your credentials)
I understand why I was getting that error. I have since changed things around so the code underneath this text will be different from the one above. However, I am receiving another error now: 405 This method is not allowed on this resource.
Let me explain in detail what I am doing. I am making a proxy call first to receive all of the information necessary to upload to S3. In that proxy call, I am calling aws4.sign with these options:
params.file
is:
fd = new FormData
fd.append 'file', file[0]
params.contentType
is:
'application/pdf'
var opts = {
host: "https://s3.amazonaws.com/bucket-name/" + params.filename,
method: 'POST',
service: 's3',
region: 'us-east-1',
headers: {
'Content-Type': params.contentType
},
body: params.file
};
aws_credentials = {
secretAccessKey: 'DUMMY_KEY',
accessKeyId: 'DUMMY_KEY'
};
aws4.sign(opts, aws_credentials);
return opts
Then I return those values to the client. When the user does want to upload them to S3, that is when I make another server call. Again, I am using request-promise because I need the request to be promised.
opts = {
uri: host,
method: method,
headers: [
{
Authorization: headers.Authorization,
'Content-Length': headers['Content-Length'],
'Content-Type': headers['Content-Type'],
Host: headers.Host,
'X-Amz-Content-Sha256': headers['X-Amz-Content-Sha256'],
'X-Amz-Date': headers['X-Amz-Date']
}
],
body: body
};
These values are the same as the values from above.
Then, I do: request(opts, function(response) { ..... })
and receive 405 This method is not allowed on this resource.
. I believe that this is an issue with my bucket policy. However, I have access to POST objects to an S3 bucket and CORS allows POST.
I am having the same issue, this is my configuration:
Auth.currentCredentials().then((creds: AmplifyUserCredentials) => {
const credentials = Auth.essentialCredentials(creds);
const request = {
host: 'myapi.com/',
service: 'execute-api',
baseURL: 'http://'myapi.com/',
region: 'eu-west-1',
method: 'GET',
path: '/',
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
'Accept': 'application/json',
'Content-Type': 'application/json'
}
};
const signedRequest = sign(request,
{
secretAccessKey: credentials.secretAccessKey,
accessKeyId: credentials.accessKeyId,
sessionToken: credentials.sessionToken
}
);
delete signedRequest.headers['Host'];
// delete signedRequest.headers['Content-Length']; (Update: removed)
Axios.get('helloworld/', signedRequest)
.then((data) => {
console.log(data);
})
.catch((error) => {
console.log(error);
});
});
The current Headers, their configuration and values seem alright, I've tested so many different ways, like leaving just the method, host, service and path
into the request, removing the headers, changing the CORS value, but the never seems to work. The aws4
generated Signature
is different than the one aws generates or expects.
{"data": "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details."}
@iarroyo5 In your case, I believe it is because you are deleting two properties from your signed request. What I have learned is that when you sign the request, you must act as if the data is immutable. If you change any one piece of that data that you have signed, you will receive that error.
Hi @chasen-bettinger, thanks for your fast reply, but, that was my first thought. I can't leave Host
into the headers
as the browser refuse it with this error on the console:
xhr.js?b50d:126 Refused to set unsafe header "Host"
and even in this case (with no Host
), the response is still responding with 403
status and with this message of error:
{"data": "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details".
Results
Credential
is generated 👍
SignedHeaders
is generated 👍
Signature
is generated 👎 (the hash is different than aws is returning on the 403
response)
Host
property to the headers
object? In that case, I'll be able to keep my object Immutable.Posible response: Don't think this is the problem as checking the source code of Amplify
it also removes the Host
header https://github.com/aws-amplify/amplify-js/blob/master/packages/api/src/RestClient.ts#L262
aws
has changed the sign algorithms?execute-api
service, are you sure the signature is working for this service?Update
hash(this.canonicalString(), 'hex'),
function in RequestSigner.prototype.stringToSign = function()
which is generating the wrong hash, but not sure why this is happening. After a long process of debugging and comparing the input and the output of the @aws-amplify/core/Signer
class, I've made it work with this specific configuration on the request
object:
const request = {
method: 'GET',
url: 'https://myapi.com/helloworld/',
host: 'myapi.com',
path: '/helloworld/',
service: 'execute-api',
region: 'eu-west-1',
data: null
};
For everyone with the same kind of problem like I had, make sure you are adding the the trailing /
on the path
, on url
and not on the host
@iarroyo5 aws4
doesn't support the url
or data
properties here – you can safely leave them out
(and method
is GET
by default)
I've just checked without those three keys and it also works.
const request = {
host: 'api.mylivepigeon.com',
path: '/helloworld/',
service: 'execute-api',
region: 'eu-west-1'
};
Closing this out – not an issue with aws4
In my case I was using s3.getSignedUrl('getObject')
when I needed to be using s3.getSignedUrl('putObject')
, which is why the signatures didn't match.
and later when I make the network request... Using the request-promise library.