1

Ok so I am trying to build a small twitter client for Windows 8 using Javascript and WinJS. I have gotten as far as obtaining the request oauth tokens as well as the oauth verifier. One of Microsoft's templates was a great resource for this. I can't seem to find really any help online for Javascript and oAuth though. Anyways here's my code. I need to figure out to get the oAuth access tokens form here and store them.

////
////    The function of this file is to connect with Twitter via oAuth
////

(function () {
    "use strict";

    //Define a namespace to keep track of controls 
    WinJS.Namespace.define("Account", {
        options: {                                                          // This is the object containing the apps
            consumerKey: ********,                          // Twitter credentials
            consumerSecret: **********,
            callback: *************
        }
    });

    Account.sendRequest = function (url) {
        try {
            var request = new XMLHttpRequest();
            request.open("GET", url, false);
            request.send(null);
            return request.responseText;
        } catch (err) {
            WinJS.log("Error sending request: " + err, "Web Authentication SDK Sample", "error");
        }
    };

    Account.sendPostRequest= function(url, authzheader) {
        try {
            var request = new XMLHttpRequest();
            request.open("POST", url, false);
            request.setRequestHeader("Authorization", authzheader);
            request.send(null);
            return request.responseText;
        } catch (err) {
            WinJS.log("Error sending request: " + err, "Web Authentication SDK Sample", "error");            
        }
    };

    Account.getVerifier = function (returned) {
        var URLstring = returned;    //returned;
        var oauth_token;
        Account.oauth_verifier = "";
        URLstring = URLstring.substring("http://novodevelopment.tk/?".length);
        var valuePairs = URLstring.split("&");
        for (var i = 0; i < valuePairs.length; i++) {
            var splits = valuePairs[i].split("=");
            switch (splits[0]) {
                case "oauth_token":
                    oauth_token = splits[1];
                    break;
                case "oauth_verifier":
                    Account.oauth_verifier = splits[1];
                    console.log("oAuth Verifier: " + Account.oauth_verifier);
                    break;
            }
        }
    };

    Account.convertTokens = function (url, authzheader) {
        try {
            var request = new XMLHttpRequest();
            request.open("POST", url, false);
            request.setRequestHeader("Authorization", authzheader);
            request.setRequestHeader("oauth_verifier", Account.oauth_verifier);
            reqest.send(null);
            return request.responseText;
        } catch (err) {
            console.log("failure");
        }

    };

    Account.authzInProcess = false;

    Account.launchTwitterWebAuth = function () {
        var twitterURL = "https://api.twitter.com/oauth/request_token";

        // Get all parameters
        var clientID = Account.options.consumerKey;
        var clientSecret = Account.options.consumerSecret;
        var callBackURL = Account.options.callback;

        // Get Date
        var timestamp = Math.round(new Date().getTime() / 1000.0);

        // Create a nonce
        var nonce = Math.random();
        nonce = Math.floor(nonce * 1000000000);

        // Compute base signature string and sign it.
        //    This is a common operation that is required for all requests even after the token is obtained.
        //    Parameters need to be sorted in alphabetical order
        //    Keys and values should be URL Encoded.
        //    To be fair I found all of this part online
        //    It basically serves the same purpose as jsOAuth
        var sigBaseStringParams = "oauth_callback=" + encodeURIComponent(Account.options.callback);
        sigBaseStringParams += "&" + "oauth_consumer_key=" + clientID;
        sigBaseStringParams += "&" + "oauth_nonce=" + nonce;
        sigBaseStringParams += "&" + "oauth_signature_method=HMAC-SHA1";
        sigBaseStringParams += "&" + "oauth_timestamp=" + timestamp;
        sigBaseStringParams += "&" + "oauth_version=1.0";
        var sigBaseString = "POST&";
        sigBaseString += encodeURIComponent(twitterURL) + "&" + encodeURIComponent(sigBaseStringParams);

        var keyText = clientSecret + "&";
        var keyMaterial = Windows.Security.Cryptography.CryptographicBuffer.convertStringToBinary(keyText, Windows.Security.Cryptography.BinaryStringEncoding.Utf8);
        var macAlgorithmProvider = Windows.Security.Cryptography.Core.MacAlgorithmProvider.openAlgorithm("HMAC_SHA1");
        var key = macAlgorithmProvider.createKey(keyMaterial);
        var tbs = Windows.Security.Cryptography.CryptographicBuffer.convertStringToBinary(sigBaseString, Windows.Security.Cryptography.BinaryStringEncoding.Utf8);
        var signatureBuffer = Windows.Security.Cryptography.Core.CryptographicEngine.sign(key, tbs);
        var signature = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(signatureBuffer);
        var dataToPost = "OAuth oauth_callback=\"" + encodeURIComponent(Account.options.callback) + "\", oauth_consumer_key=\"" + clientID + "\", oauth_nonce=\"" + nonce + "\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"" + timestamp + "\", oauth_version=\"1.0\", oauth_signature=\"" + encodeURIComponent(signature) + "\"";
        var response = Account.sendPostRequest(twitterURL, dataToPost);
        var oauth_token;
        var oauth_token_secret;
        var keyValPairs = response.split("&");

        for (var i = 0; i < keyValPairs.length; i++) {
            var splits = keyValPairs[i].split("=");
            switch (splits[0]) {
                case "oauth_token":
                    oauth_token = splits[1];
                    break;
                case "oauth_token_secret":
                    oauth_token_secret = splits[1];
                    break;
            }
        }

        // Send user to authorization page
        twitterURL = "https://api.twitter.com/oauth/authorize?oauth_token=" + oauth_token;

        var startURI = new Windows.Foundation.Uri(twitterURL);
        var endURI = new Windows.Foundation.Uri(Account.options.callback);

        Account.authzInProgress = true;

        Windows.Security.Authentication.Web.WebAuthenticationBroker.authenticateAsync(
            Windows.Security.Authentication.Web.WebAuthenticationOptions.none, startURI, endURI)
            .done(function (result) {
                console.log("Authenticated URL: " + result.responseData);
                var returnData = result.responseData;
                Account.getVerifier(returnData);
                Account.authzInProgress = false;
            }, function (err) {
                console.log("Error returned by WebAuth broker: " + err, "Web Authentication SDK Sample", "error");
                Account.authzInProgress = false;
            });

        var authzheader = {
            oauth_consumer_key: clientID,
            oauth_nonce: nonce,
            oauth_signature: signature,
            oauth_signature_method: "HMAC-SHA1",
            oauth_timestamp: timestamp,
            oauth_token: oauth_token,
            oauth_version: "1.0"
        };
        var twitterURL = "https://api.twitter.com/oauth/access_token";
   //     var converted = Account.convertTokens(twitterURL);


        Account.convertTokens(twitterURL);

    };



})();

Sorry that its a bit of a mess

makerofthings7
  • 60,103
  • 53
  • 215
  • 448
charrondev
  • 1,129
  • 2
  • 9
  • 13
  • Instead of using Math.random(), you should use `CryptographicBuffer.GenerateRandomNumber()` – Josh E Oct 06 '12 at 18:08

2 Answers2

0

To store informations you can use the Windows.Storage.ApplicationData class which allows you to store local/roaming settings/files.

I'll suggest you to use roaming settings/files since there are accessible by your application through different devices which means if you have your app installed on two devices, desktop and laptop for example, you can access the stored information from both devices. The association is done through the LiveID.

If you're not logged with a LiveID or if you don't have an internet connection (which in the present case will be a bit problematic for a Twitter client J ) the settings/files are persisted locally.

I hope this help.

Aymeric
  • 1,089
  • 7
  • 10
  • if you're planning on storing the token, you should absolutely, positively, use `Windows.Security.Credentials.CredentialVault`to store them. Not as flexible as the application data, but far better to leave the security aspects to people who spend a lot more time on it than you or I – Josh E Oct 05 '12 at 19:49
0

I solved this, but because of NDA with my employer I may not be able to share much of the code.

Take a look at this this blog:

http://www.wackylabs.net/2011/12/oauth-and-flickr-part-2/

I was failing to convert the request token to an access token because the secret I was using was incorrect.

I was blindly doing using: app_secret + '&' for my key material.

When you go to upgrader, you need app_secret + '&' + oauth_token_secret.

This might not make much sense, but if you want more info must message me.

  • hi, could you please share more info with me. I'm working on Goodreads API using web authentication broker. I can successfully get oauth token and secret. But I have no idea how to get the access token. thanks – Harshani Mar 18 '13 at 14:33