So the question I asked was "Could I write a script to authenticate using OAuth and retrieve data from the Twitter REST API?"
Obviously, the first place I looked was in the OAuthConfig class of the UrlFetchApp. I set up the configuration and tried to make a call but I kept getting an authentication error. A little research showed that I wasn't the only one having this problem. The issue stems from the fact that normally, users need to authenticate through some sort of dialog box before they can access data. See this example about connecting to Picasa Web Albums for more details.
But then I found a post about someone managing to get around this by re-implementing the OAuth authentication system in their script and using a standard UrlFetchApp.fetch() request.
I was up for a challenge so I recreated it myself. It turned out to be quite a bit of code, but in the end, the only thing you really need to worry about is getting the correct keys from Twitter and calling _build_authorization_string().
Thanks,
Russ
//----------------------------------- // Authenticate and Connect to OAuth Service // Created By: Russ Savage // FreeAdWordsScripts.com //----------------------------------- function main() { //Define the Twitter Keys and Secrets //More info on obtaining these can be found at https://dev.twitter.com/docs/auth/tokens-devtwittercom var oauth_key_stuff = { "consumer_key" : "your consumer key", "consumer_secret" : "your consumer secret", "access_token" : "your access token", "access_token_secret" : "your access token secret" }; // Update this with the REST url you want to call. I only tested it with GET // but i don't think there is anything stopping a POST request from working. var url_stuff = { "http_method" : 'GET', "base_url" : "https://api.twitter.com/1.1/statuses/user_timeline.json" }; //Add the parameters for the REST url you want to call. var url_param_stuff = { "screen_name" : "russellsavage" //hey that's me! }; // Don't touch this stuff var other_oauth_data = { "oauth_nonce" : Utilities.base64Encode(Math.random() + "secret_sauce" + (new Date()).getTime()).replace(/(?!\w)/g, ''), "oauth_signature_method" : "HMAC-SHA1", "oauth_timestamp" : Math.round((new Date()).getTime() / 1000.0), "oauth_version" : "1.0" }; // Here is where the magic happens var auth_string = _build_authorization_string(oauth_key_stuff,url_stuff,url_param_stuff,other_oauth_data); var options = { "headers" : { "Authorization" : auth_string } }; var url = _build_url(url_stuff,url_param_stuff); var response = UrlFetchApp.fetch(url, options); var tweets = JSON.parse(response.getContentText()); //now let's log my amazing tweets! for(var tweet in tweets) { var t = tweets[tweet]; Logger.log(t.text); } // HELPER FUNCTIONS BELOW function _build_url(base_url,param_stuff){ var url = base_url.base_url; if(param_stuff != {}) { url += '?'; } for(var key in param_stuff) { url += key + "="; url += encodeURIComponent(param_stuff[key]); url += '&'; } return url.slice(0,-1); } function _build_param_string(auth_keys,url_data,oauth_data) { var data_for_param_string = { "oauth_consumer_key" : auth_keys.consumer_key, "oauth_nonce" : oauth_data.oauth_nonce, "oauth_signature_method" : oauth_data.oauth_signature_method, "oauth_timestamp" : oauth_data.oauth_timestamp, "oauth_token" : auth_keys.access_token, "oauth_version" : oauth_data.oauth_version }; // add additional url values for(var my_key in url_data) { data_for_param_string[my_key] = url_data[my_key]; } // find and sort the keys for later var keys = []; for(var key in data_for_param_string) { keys.push(key); } keys.sort(); //finally build and return the param string var param_string = ""; for(var i in keys) { param_string += keys[i] + "=" + encodeURIComponent(data_for_param_string[keys[i]]); if(i < keys.length - 1) { param_string += "&"; } } return param_string; } function _build_sig_base_string(my_url_stuff,my_param_string) { return my_url_stuff.http_method + "&" + encodeURIComponent(my_url_stuff.base_url) + "&" + encodeURIComponent(my_param_string); } function _build_sigining_key(my_key_stuff) { return encodeURIComponent(my_key_stuff.consumer_secret) + "&" + encodeURIComponent(my_key_stuff.access_token_secret); } function _build_oauth_signature(base_string,sign) { return Utilities.base64Encode( Utilities.computeHmacSignature( Utilities.MacAlgorithm.HMAC_SHA_1, base_string, sign ) ); } function _build_authorization_string(my_key_stuff,my_url_stuff,my_url_param_stuff,my_oauth_stuff) { var param_string = _build_param_string(my_key_stuff,my_url_param_stuff,my_oauth_stuff); var sig_base_string = _build_sig_base_string(my_url_stuff,param_string); var signing_key = _build_sigining_key(my_key_stuff); var oauth_signature = _build_oauth_signature(sig_base_string,signing_key); return "OAuth " + encodeURIComponent("oauth_consumer_key") + '="' + encodeURIComponent(my_key_stuff.consumer_key) + '", ' + encodeURIComponent("oauth_nonce") + '="' + encodeURIComponent(my_oauth_stuff.oauth_nonce) + '", ' + encodeURIComponent("oauth_signature") + '="' + encodeURIComponent(oauth_signature) + '", ' + encodeURIComponent("oauth_signature_method") + '="' + encodeURIComponent(my_oauth_stuff.oauth_signature_method) + '", ' + encodeURIComponent("oauth_timestamp") + '="' + encodeURIComponent(my_oauth_stuff.oauth_timestamp) + '", ' + encodeURIComponent("oauth_token") + '="' + encodeURIComponent(my_key_stuff.access_token) + '", ' + encodeURIComponent("oauth_version") + '="' + encodeURIComponent(my_oauth_stuff.oauth_version) + '"'; } }