I'm trying to get to grips with the amazonka library. I want to pre-sign a PUT request for S3. Looking at the example here, I put together the code below. It doesn't work when trying to send up a JPEG image from the client side. AWS complains that the signature is not correct.
My client-side code works with the nodejs aws sdk, so I can only guess that I am configuring things incorrectly here.
<Error>
<Code>
SignatureDoesNotMatch
</Code>
<Message>
The request signature we calculated does not match the signature you provided. Check your key and signing method.
</Message>
<CanonicalRequest>
PUT
/my-bucket/test.jpg
X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-
Credential=[MY_AWS_ACCESS_KEY]%2F20171010%2Feu-west-
1%2Fs3%2Faws4_request&X-Amz-Date=20171010T084724Z&X-Amz-
Expires=100000&X-Amz-SignedHeaders=expect%3Bhost
expect:
host:s3-eu-west-1.amazonaws.com
expect;host
UNSIGNED-PAYLOAD
</CanonicalRequest>
...
Here's my code:
getS3UrlR :: Handler Value
getS3UrlR = do
y <- getYesod
let settings = appSettings y
env <- newEnv $ FromKeys (AccessKey $ encodeUtf8 $ appAwsAccessKey settings) (SecretKey $ encodeUtf8 $ appAwsSecretKey settings)
ts <- liftIO $ getCurrentTime
let b = BucketName $ appS3Bucket settings
k = ObjectKey "profile-pic-test"
url <- liftIO $ runResourceT . runAWST env . within Ireland $ presignURL ts 100000 (putObject b k (toBody ("" :: ByteString)))
return $ toJSON $ decodeUtf8 url
How can I go about debugging this?
Note - putObject requires a RqBody argument, but I don't have one to provide (as the client is going to supply the request body). So I just supplied an empty string. Could that be a problem?
Edit - I tried signing a GET request to see if that would work. It works fine! But PUT does not. This is the changed line that works fine:
url <- liftIO $ runResourceT . runAWST env . within Ireland $ presignURL ts 100000 (getObject b k)