I'm using a custom PHP script to submit requests to the mturk API, based on the signature functions from the PHP-AWS library. Here's an example of a request:
https://mechanicalturk.amazonaws.com/?Service=AWSMechanicalTurkRequester&AWSAccessKeyId=MYKEY&Version=2012-03-25&Operation=NotifyWorkers&Signature=j+4UTX9x3EKltvWpoxIkp4BM6S4=&Timestamp=2015-06-25T09:37:51Z&Subject=test&MessageText=just+testing+&WorkerId.1=SOMEID
Sometimes a given script will work, and at other times the same script will return an error like this:
AWS.BadClaimsSupplied The specified claims are invalid. Based on your request, your signature should be generated using the following string: AWSMechanicalTurkRequesterNotifyWorkers2015-06-25T09:37:51Z. Check to make sure your system clock and timezone is not incorrect. Our current system time: 2015-06-25T09:37:51Z. (1435225071849)
When I get the AWS.BadClaimsSupplied
error, repeatedly rerunning the script will cause it to eventually work. By "work," I mean that either API returns true
and the desired action is taken, or it returns an error that's relevant to the action I'm requesting.
I assume that if I were performing the hash incorrectly or with the wrong signature, then it would never work*. The intermittent nature of the problem makes me think it's a timing error. But the example above shows an error message in which the time I used for my signature is the same as their time, so that doesn't seem like the problem either.
*okay, it would work once in every 2^160 tries.
I tried backdating my timestamps by 1 second just in case I was a little ahead of them; that didn't change the results. I can't think of any other way to debug this.
The error message makes it sound like the problem is with the string being hashed, but the actual problem is that some hashed strings include special characters. The characters
+
,/
, and=
affect how the URL is parsed and will interfere with reading your signature. Rerunning the request with a different time string will randomly return a hash without those characters, allowing the request to work.Solution: Simply run
urlencode()
on the signature before making the API call. If for some reason you don't want to do that, this answer provides some code that encodes those specific characters only, but I think the standard function is more comprehensive and safer.