I am trying something a little specific, namely trying to call a REST API. I have been following these instructions.
I have been very careful to ensure that I am creating the "Signature base string" correctly. They define it to be created like this:
(HTTP Method)&(Request URL)&(Normalized Parameters)
You can double check if need be in my code, but I am very sure that it is fine.
The problem that I am having is creating what they call the "oauth signature" and mine isn't matching theirs. They it should be created like this:
Use the HMAC-SHA1 signature algorithm as defined by the [RFC2104] to sign the request where text is the Signature Base String and key is the concatenated values of the Consumer Secret and Access Secret separated by an '&' character (show '&' even if Access Secret is empty as some methods do not require an Access Token).
The calculated digest octet string, first base64-encoded per [RFC2045], then escaped using the [RFC3986] percent-encoding (%xx) mechanism is the oauth_signature.
I express this in my code like so:
var oauthSignature = CryptoJS.HmacSHA1(signatureBaseString, sharedSecret+"&");
var oauthSignature64 = encodeURIComponent(CryptoJS.enc.Base64.stringify(oauthSignature));
console.log("hash in 64: " + oauthSignature64);
I am using Google's CryptoJS library. I take the signature base string as the text, I then take my consumer secret as the key concatenated with "&", I have no Access key and it isn't required but that is OK. I then base 64 encode the result of that hash, after which I URI encode it, please could some guys sanity check my understanding of that and my usage/expressing of it in code using this library, I think this is where my problem is.
Here is my full code:
var fatSecretRestUrl = "http://platform.fatsecret.com/rest/server.api";
var d = new Date();
var sharedSecret = "xxxx";
var consumerKey = "xxxx";
//this is yet another test tyring to make this thing work
var baseUrl = "http://platform.fatsecret.com/rest/server.api?";
var parameters = "method=food.search&oauth_consumer_key="+consumerKey+"&oauth_nonce=123&oauth_signature_method=HMAC-SHA1&oauth_timestamp="+getTimeInSeconds()+"&oauth_version=1.0&search_expression=banana";
var signatureBaseString = "POST&" + encodeURIComponent(baseUrl) + "&" + encodeURIComponent(parameters);
console.log("signature base string: " + signatureBaseString);
var oauthSignature = CryptoJS.HmacSHA1(signatureBaseString, sharedSecret+"&");
var oauthSignature64 = encodeURIComponent(CryptoJS.enc.Base64.stringify(oauthSignature));
console.log("hash in 64: " + oauthSignature64);
var testUrl = baseUrl+"method=food.search&oauth_consumer_key=xxxx&oauth_nonce=123&oauth_signature="+oauthSignature64+"&oauth_signature_method=HMAC-SHA1&oauth_timestamp="+getTimeInSeconds()+"&oauth_version=1.0&search_expression=banana";
console.log("final URL: " + testUrl);
var request = $http({
method :"POST",
url: testUrl
});
I have taken care to ensure that the parameters that I am posting are in lexicographical order and I am very sure that it is correct.
The response that I am getting back is:
Invalid signature: oauth_signature 'RWeFME4w2Obzn2x50xsXujAs1yI='
So clearly either
- I haven't understood the instructions provided in the API
- Or I have understood them but I haven't expressed them in that way in my code
- Or both of the above
- Or I have made some subtle mistake somewhere that I can't see
I would really appreciate a sanity check, this has taken a while.