Amazon S3 Signature Does Not Match - AWS SDK Java

Doubt the OP still has a problem with this, but for anyone else who runs into this, here is the answer:

When making a signed request to S3, AWS checks to make sure that the signature exactly matches the HTTP Header information the browser sent. This is unfortunately required reading: http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html

However in the code above this is not actually the case, the Javascript is sending:

xhr.setRequestHeader('Content-Type', 'image/png');
xhr.setRequestHeader('x-amz-acl', 'authenticated-read');

But in the Java/Scala, s3.generatePresignedUrl is being called without passing in either of them. So the resulting signature is actually telling S3 to reject anything with a Content-Type or x-ams-acl header set. Oops (I fell for it too).

I've seen browsers send Content-Types automatically, so even if they're not explicitly added to the header they could still be coming into S3. So the question is, how do we add Content-Type and x-amz-acl headers into the signature?

There are several overloaded generatePresignedUrl functions in the AWS SDK, but only one of them allows us to pass in anything else besides the bucket-name, filename, expiration-date and http-method.

The solution is:

  1. Create a GeneratePresignedUrlRequest object, with your bucket and filename.
  2. Call setExpiration, setContentType, etc, to set all of your header info on it.
  3. Pass that into s3.generatePresignedUrl as the only parameter.

Here's the proper function definition of GeneratePresignedUrlRequest to use:

http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/AmazonS3Client.html#generatePresignedUrl(com.amazonaws.services.s3.model.GeneratePresignedUrlRequest)

The function's code on the AWS GitHub repo was also helpful for me to see how to code up the solution. Hope this helps.


I just encountered this problem using the NodeJs AWS SDK. It was due to using credentials that were valid, but without sufficient permissions. Changing to my admin key fixed this with no code changes!


I faced a similar issue and setting the config signatureVersion: 'v4' helped solve it in my case -

In JavaScript:

var s3 = new AWS.S3({
  signatureVersion: 'v4'
});

Adapted from https://github.com/aws/aws-sdk-js/issues/902#issuecomment-184872976