Oauth request_token Error 215 Bad Authentication Data

rest
javascript

#1

HELP SOUGHT:
Update: I have tried using Chrome Postman to make the request_token call, but get the same result. I have extensively debugged my code against both the Twitter and OAuth.net examples. My keys work with twurl, but I’m stumped as to why they don’t work in my app.

I’m trying to authenticate using Javascript minimising use of external libraries. I’m using a php server proxy to forward the request, but I’m trying to run the logic client-side. I intend to use Apache Cordova, but this is just a desktop Proof-Of-Concept.

At this stage, I’m stuck at the request token stage. I get error 215, but this doesn’t tell me what I’ve done wrong. I’ve debugged as much as I can. I have run the logic on the examples given for Authorization and the resulting Bas64’d hash is right.

So either the error lies in my call-back, time-stamp or nonce, values or I’m constructing the header-string wrong.

Here is the logic, code and output:
LOGIC:
set path

[code]
function authorize(){
var path = ‘oauth/request_token’;// The web services request minus the domain name
var url = ‘http://[mydomain].org/PhoneApp/twitterProxy.php?yws_path=’ + encodeURIComponent(path);// The full path to the PHP proxy
[end code]

set method

[code]
var method = ‘POST’;
[end code]

set parameters

var oauth_callback = encodeURIComponent("http://[mydomain].org/PhoneApp/input.html");
var oauth_consumer_key = encodeURIComponent("[consumer key was here]");
var oauth_nonce = encodeURIComponent(generateNonce());
var oauth_signature_method = encodeURIComponent("HMAC-SHA1"); 
var oauth_timestamp = encodeURIComponent(Math.floor(new Date().getTime()/1000));
var oauth_version = encodeURIComponent("1.0");

generate parameter base from all the parameters

Percent encode every key and value that will be signed. // keys don't need it, but I did it anyway
Sort the list of parameters alphabetically by encoded key.
For each key/value pair:
Append the encoded key to the output string.
Append the ‘=’ character to the output string.
Append the encoded value to the output string.
If there are more key/value pairs remaining, append a ‘&’ character to the output string.

[code]
var parameter_base=encodeExcMark(
encodeURIComponent(“oauth_callback”)+"="+oauth_callback
+"&"+encodeURIComponent(“oauth_consumer_key”)+"="+oauth_consumer_key
+"&"+encodeURIComponent(“oauth_nonce”)+"="+oauth_nonce
+"&"+encodeURIComponent(“oauth_signature_method”)+"="+oauth_signature_method
+"&"+encodeURIComponent(“oauth_timestamp”)+"="+oauth_timestamp
+"&"+encodeURIComponent(“oauth_version”)+"="+oauth_version);
[/end code]

Create the signature base string

The three values collected so far must be joined to make a single string, from which the signature will be generated. This is called the signature base string by the OAuth specification.

To encode the HTTP method, base URL, and parameter string into a single string:

Convert the HTTP Method to uppercase and set the output string equal to this value.
Append the ‘&’ character to the output string.
Percent encode the URL and append it to the output string.
Append the ‘&’ character to the output string.
Percent encode the parameter string and append it to the output string.

[code]
var signature_base = encodeURIComponent(method)+"&"+encodeURIComponent(url)+"&"+encodeURIComponent(parameter_base);
[end code]

Set consumer_secret variable and generate signing key

[code]
var consumer_secret = “[consumer key secret was here]”;
var signing_Key = consumer_secret+"&";//token_secret not used in request_token
var hash = CryptoJS.lib.WordArray.create();
hash = CryptoJS.HmacSHA1(signature_base, signing_Key);
var oauth_signature=CryptoJS.enc.Base64.stringify(hash);
[end code]

NOTE: all the above logic has been successfully tested on the sample data from the Twitter site, generating matching results at all stages. If the error is in the prior code, it must be in the values I have generated, which are the timestamp, the nonce or the call-back. I have no way of testing these. Otherwise the header is wrong.

Generate the header, which is Oauth plus all the above in one string

Append the string “OAuth ” (including the space at the end) to DST.
For each key/value pair of the 7 parameters listed above:
Percent encode the key and append it to DST.
Append the equals character ‘=’ to DST.
Append a double quote ‘”’ to DST.
Percent encode the value and append it to DST.
Append a double quote ‘”’ to DST.
If there are key/value pairs remaining, append a comma ‘,’ and a space ’ ’ to DST.

Note: All values except oauth_signature have already been %encoded
Note: order of keys as per example

[code]
var header=“OAuth “
+“oauth_nonce=””+oauth_nonce
+”", oauth_callback=""+oauth_callback
+"", oauth_signature_method=""+oauth_signature_method
+"", oauth_timestamp=""+oauth_timestamp
+"", oauth_consumer_key=""+oauth_consumer_key
+"", oauth_signature=""+encodeURIComponent(oauth_signature)
+"", oauth_version=""+oauth_version
+""";
xmlHttp.open( “POST”, url, true );
xmlHttp.setRequestHeader(“Authorization”, header);
xmlHttp.onreadystatechange = processRequest;
xmlHttp.send( null );
xmlHttp.close;
}
[end code]

Helper functions called:
generateNonce()
encodeExcMark()

[code]
function generateNonce(length) {//borrowed from https://github.com/jrconlin/oauthsimple/blob/master/js/OAuthSimple.js
if (length === undefined) {
length = 32;
}
var result = ‘’,
i = 0,
rnum,
nonce_chars = ‘0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz’;
cLength = nonce_chars.length;
for (; i < length; i++) {
rnum = Math.floor(Math.random() * cLength);
result += nonce_chars.substring(rnum, rnum + 1);
}
return result;
};

function encodeExcMark(inString)//encodeURIComponent() doesn’t encode !, Twitter requires it
{
return inString.replace("!", “%21”);
}
[end code]

OUTPUT: (single line, space after commas, ‘’ added to show follow-on
Authorization:
OAuth oauth_nonce=“InsAGEaSyNXZZ8I0V13Zsc8P9bvehJi4UueTj5luWz”,
oauth_callback=“http%3A%2F%2F[my domain].org%2FPhoneApp%2Finput.html”,
oauth_signature_method=“HMAC-SHA1”,
oauth_timestamp=“1463756963”,
oauth_consumer_key="[consumer key was here]",
oauth_signature=“6duMk1pnVPwHUHJZ3nDazou13S8%3D”,
oauth_version=“1.0”

Compare to sample:
Authorization Header:
OAuth oauth_nonce=“K7ny27JTpKVsTgdyLdDfmQQWVLERj2zAK5BslRsqyw”,
oauth_callback=“http%3A%2F%2Fmyapp.com%3A3005%2Ftwitter%2Fprocess_callback”,
oauth_signature_method=“HMAC-SHA1”,
oauth_timestamp=“1300228849”,
oauth_consumer_key=“OqEqJeafRSF11jBMStrZz”,
oauth_signature=“Pc%2BMLdv028fxCErFyi8KXFM%2BddU%3D”,
oauth_version=“1.0”

Registered callback:
http://[mydomain].org/PhoneApp/callback

RESULT:
Status 200
type json
{“errors”:[{“code”:215,“message”:“Bad Authentication data.”}]}