763 Tage zuvor: Twitter-Home als Feed mit Javascript

Vor gut zwei Jahren hat Twitter einen wichtigen Schritt zur Datensicherheit gemacht. Mit Einf├╝hrung ihrer API 1.1 wurde zum Ausf├╝hren vieler Funktionen eine OAuth Authentifizierung n├Âtig. Und bei der Implementierung in (Web-) Applikationen ist dies auch meistens kein Problem. Anders sieht es da schon mit JavaScript aus.

Generell ist von einer Implementierung von OAuth in JavaScript auch deutlich abzuraten! Da die privaten Schl├╝ssel zur einer eindeutigen Identifizierung im Klartext dem Client vorliegen m├╝ssen, gibt es keine M├Âglichkeit diese ausreichend vor Fremdzugriff zu sch├╝tzen. F├╝r mein letzte Projekt, eine personalisierte Browser-Startseite, war jedoch eine Server-seitige Implementation nicht zielf├╝hrend.

kbo Startpage

Beim Herausarbeiten der Funktionalit├Ąt stie├č ich immer wieder auf Aussagen das dies generell nicht m├Âglich sei (sogar von Twitter-Mitarbeitern). Selbstredend ist dies nicht korrekt; wenn auch die Implementation, vor allem dank des faszinierenden Signatur-Prozesses, durchaus herausfordernd ist. Um meinen Teil zum aufr├Ąumen mit diesem Ger├╝cht beizutragen, hier jedenfalls die Fr├╝chte meiner Arbeit.

Um das Skript auszuf├╝hren ben├Âtigt man:

  1. Eine Twitter-App (zu erstellen)
  2. Authentifizierten Zugriff der App auf das eigene Profil
  3. Die CryptoJS library (hmac-sha1.js reicht)
  4. jQuery (zumindest in dem Beispiel)

F├╝llt man die Variablen f├╝r Consumer und Access Token aus, sollte der Aufruf von loadTwitter() das Array tweets[] mit den letzten Tweets der Twitter Home-Timeline bef├╝llen. Und die kann man dann, zum Beispiel, in einer personalisierten Startseite verwenden.

/*
 * Retrieve Tweets from your personal Twitter home via REST.
 * (c)2015 by Kai Boenke [code@boenke.info]
 * Requires CryptoJS (hmac-sha1.js): https://code.google.com/p/crypto-js/
 * Requires jQUery: https://jquery.com/
 */
var tweets = [];
function loadTwitter(){
	twitterURL =			"https://api.twitter.com/1.1/statuses/home_timeline.json";
	twitterURLmethod =		"GET",
	twitterKey =			"xxxxxxxxxxxxxxxxxxxxxxxxx"; //Consumer Key (User)
	twitterSecret =			"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; //Consumer Secret (User)
	twitterToken =			"99999999-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; //Access Token (App)
	twitterTokenSecret =	"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; //Access Token Secret (App)
	twitterNonce =			getNonce(32);
	twitterTimestamp =		Math.round(Date.now()/1000);
	
	// Generate oAuth Signature (https://dev.twitter.com/oauth/overview/creating-signatures)
	twitterParameter = [
		encodeURI('oauth_consumer_key='+twitterKey),
		encodeURI('oauth_nonce='+twitterNonce),
		encodeURI('oauth_signature_method='+"HMAC-SHA1"),
		encodeURI('oauth_timestamp='+twitterTimestamp),
		encodeURI('oauth_token='+twitterToken),
		encodeURI('oauth_version='+"1.0")
	];
	twitterParameter.sort();
	twitterSignatureBase =	twitterURLmethod +"&"+ encodeURIComponent(twitterURL) +"&"+ encodeURIComponent(twitterParameter.join("&"));
	twitterSignatureKey =	encodeURIComponent(twitterSecret) +"&"+ encodeURIComponent(twitterTokenSecret);
	twitterSignature =		encodeURIComponent(CryptoJS.HmacSHA1(twitterSignatureBase, twitterSignatureKey).toString(CryptoJS.enc.Base64));
	
	// Get tweets
	$.ajax({
		type:		twitterURLmethod,
		url:		twitterURL,
		headers:	{
			'Authorization': 'OAuth '+
				'oauth_consumer_key="'+ twitterKey +'", '+
				'oauth_nonce="'+ twitterNonce +'", '+
				'oauth_signature="'+ twitterSignature +'", '+
				'oauth_signature_method="HMAC-SHA1", '+
				'oauth_timestamp="'+ twitterTimestamp +'", '+
				'oauth_token="'+ twitterToken +'", '+
				'oauth_version="1.0"'
		}
	}).done(function(twitterData){
		// Retrieve tweets
		$.each(twitterData, function(i, tweet){
			tweets.push({
				timestamp: (new Date(tweet.created_at)).getTime(),
				link: "https://twitter.com/"+ tweet.user.screen_name +"/status/"+ tweet.id_str,
				value: tweet.text
			});
		});
	});
}