简体   繁体   中英

Twitter OAuth1.0A Javascript Error

I'm currently working on incorporating an authorization feature for Twitter following the approach described here: https://dev.twitter.com/docs/auth/implementing-sign-twitter . I'm using Ajax to send my POST 'http' request, but I've been constantly running into a '401: Unauthorized' error. My code is below:

function getTweets() {
    var time = generateTimestamp(); 
    var nonce = generateNonce();
    var signature = generateSignature(time, nonce);
    var headers = {
          "Authorization": 'OAuth oauth_callback="http%3A%2F%2Fwww.google.com%2F", oauth_consumer_key="eEeAAz9fakedtAOlIUhPgQ", oauth_nonce="bbc34b2ca6faabogus6dfc025907fa334", oauth_signature="' + signature + '", oauth_signature_method="HMAC-SHA1", oauth_timestamp="' + time + '", oauth_version="1.0"'
    };

    $.ajax({
        type: "POST",
        url: "https://api.twitter.com/oauth/request_token",
        dataType: "text",
        headers: headers,
        success: function(data) {
            alert("Success!");
            console.log(data);
        },
        error: function(jq) {
            alert("Request Failed.");
            console.log(jq.statusText);
        }
    });
}

function generateTimestamp() {
    var currentTime = new Date;
    currentTime = Math.floor(currentTime.getTime() / 1000);
    return currentTime;
}

function generateNonce() {
    var code = "";
    for (var i = 0; i < 20; i++) {
        code += Math.floor(Math.random() * 9).toString();
    }
    return code;
}  

function generateSignature(timestamp, nonce) {
    var http_method = "POST";
    var base_url = "https://api.twitter.com/oauth/request_token";
    var consumer_key = "eEeAAz9hUKtdjunkeIUhPgQ";
    var consumer_secret = "c7wHxnjubxVDcc5hYFqnotactuallymysecretWs2XazUFde0lPRBtBQ";
    var signature_method = "HMAC-SHA1";
    var token = "609493744-kNPzLKSI4Hg9NWQnopeFPb91eXFUutFm1nZ2hDk2";
    var token_secret = "15WOJS9Ji1AXsKRkyAZrxKdsalted5Gj5ZyEAb9aVrJxI";
    var version = "1.0";
    var parameter_string = "oauth_callback=" + encodeURIComponent(base_url) + "&oauth_consumer_key=" + consumer_key + "&oauth_nonce=" + nonce + "&oauth_consumer_key=" + consumer_key + "&oauth_signature_method=" + signature_method + "&oauth_timestamp=" + timestamp +"&oauth_version=" + version; 
    var base_string = http_method + "&" + encodeURIComponent(base_url) + "&" + encodeURIComponent(parameter_string);
    var signing_key = encodeURIComponent(consumer_secret) + "&";  
    var signature = encodeURIComponent(window.btoa(CryptoJS.HmacSHA1(base_string, signing_key)));
    alert(signature);
    return signature;
}

Feel free to post below if there's any other information that would make this error clearer. Thanks.

I created a node.js library to mess around with the Twitter OAuth dance and API. Code is here, tweeter.js

You're welcome to walk through the logic for creating the header and signature (starting at line 348 )

One thing I don't see in the code you've posted and which will make a huge difference is that the signature string must be generated to include the original header, then the header must be rebuilt with the generated string. It's a huge pain and it took me a while to figure it out.

Although the code I wrote is geared toward node.js, you should be able to reuse a lot of the logic to meet your needs.

EDIT
I found a site called hueniverse documented OAuth very well. In fact, there is a utility here to build your own headers for validating your logic (select the 'Create your own' radio button).

EDIT 2

To better explain including the oauth_signature value in the header, suppose you have all of the data up to this point:

var headerObj = {
    oauth_consumer_key="123456789",
    oauth_token="11111",
    oauth_nonce="asdfghjkl%3B",
    oauth_timestamp="1341852000",
    oauth_signature_method="HMAC-SHA1",
    oauth_version="1.0"
};

You create the HMAC-SHA1 signature and receive: "jBpoONisOt5kFYOrQ5fHCSZBGkI%3D"

You would then add that return value to headerObj , giving you:

headerObj = {
    oauth_consumer_key="123456789",
    oauth_token="11111",
    oauth_nonce="asdfghjkl%3B",
    oauth_timestamp="1341852000",
    oauth_signature_method="HMAC-SHA1",
    oauth_version="1.0",
    oauth_signature="jBpoONisOt5kFYOrQ5fHCSZBGkI%3D"
};

And this modified version of headerObj is what you build your HTTP headers from.

GET / HTTP/1.1
Host: api.twitter.com:443
Authorization: OAuth realm="https://api.twitter.com/",
    oauth_consumer_key="123456789",
    oauth_token="11111",
    oauth_nonce="asdfghjkl%3B",
    oauth_timestamp="1341852000",
    oauth_signature_method="HMAC-SHA1",
    oauth_version="1.0",
    oauth_signature="jBpoONisOt5kFYOrQ5fHCSZBGkI%3D"

NOTE: I didn't verify the host/realm/port, so these are probably wrong. Check the API for those.

The reason this is done is that on Twitter's side (this is an OAuth implementation detail), the oauth_signature value is removed and the rest of the header is hashed and its return value is compared to the value sent in oauth_signature . It's sort of like a wax seal on an envelope... if the hash of the rest of the header doesn't match the hash value you sent in oauth_signature , Twitter knows not to trust the sender or the contents.

EDIT 2.5

I'm moving this from the comment to the answer.

If you check out this line in tweeter.js, you'll see the logic.

   var signature = self.oauthSignature(method, path, headerObj, query);
    headerObj.oauth_signature = qs.escape(signature);

    // concat the header object into a csv string
    var header = 'OAuth realm="Twitter API",';
    var oauthParts = [];
    for (var h in headerObj) {
        oauthParts.push(h + '="'+headerObj[h]+'"');
    }
    header+= oauthParts.join(',');

    //...

    return header;

This bit of code does as I've explained in EDIT 2, by converting a JSON object into key="value" strings stored in oauthParts[] , then joins each element in that array into a single comma-separated string which begins with OAuth realm="Twitter API",

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM