Im heutigen Beitrag möchte ich dir ein neues Tool von mir vorstellen: das OAuth Modul für Twitter! Was das ist? Kennst du einen Twitter Client (Twitter App oder TweetDeck)? Clients verbinden sich zu deinem Twitter Account und führen (in deinem Namen) Aktionen aus. Genau das kannst du nun auch mit deiner Codea-App machen. Das OAuth Modul hilft dir dabei.

Wenn du die langweilige Vorgeschichte nicht lesen willst, dann springe direkt zum Sourcecode. Viel Spaß!

Vorgeschichte

Während der Arbeit an meinem GIF-Parser¹ für Codea habe ich mich plötzlich gefragt, ob es möglich sei, Bilder direkt von Twitter zu bekommen. Mir war klar, dass ich für diese Art von Kommunikation die RESTful API Endpoints von Twitter zu nutzen hätte - so etwas ähnliches habe ich schon einmal mit GitHub gemacht. Eigentlich braucht man nur HTTP Anfragen zu versenden und JSON Daten zu empfangen, also nichts weltbewegendes, aber am Ende war es dann doch nicht so einfach.

¹ Der GIF-Parser ist noch in Arbeit und wird es Codea einmal ermöglichen GIF Dateien anzuzeigen und auch selbst zu erstellen.

Gleich nach zwei Minuten stieß ich auf etwas, dass den Namen "OAuth" trägt. Ich hatte darüber schon hier und da gelesen, aber nur oberflächlich, und wusste eigentlich nur, dass es bei einer Authentifizierung (Login) benutzt wird. GitHub verwendet es auch, aber die stellen fertig generierte Tokens zur Verfügung mit denen man sich bei jeder HTTP Anfrage authentifiziert. Es wird also alles, mehr oder weniger, bereitgestellt. Bei Twitter schien dies aber anders. Schon nach kurzem Blättern in der Dokumentation begann ich zu begreifen, dass ich den Algorithmus wohl selbst programmieren müsse.

Zunächst sei gesagt, dass jede Twitter Anfrage über HTTP in irgendeiner Form autorisiert sein muss, d.h. ohne eine 'Autorisierung' geht nichts! Bei einer HTTP Anfrage, müssen einige Informationen mitgesendet werden: unter anderem die URL, die Methode (GET, POST,..), Zeitpunkt der Anfrage, geheime Tokens und ähnliches. Bevor die Anfrage endgültig an den Server geht, wird das alles in einen einzigen String übersetzt und verschlüsselt. Diesen String nennt man OAuth Authorization Header und das ist eben wofür OAuth zuständig ist.
Sobald die Anfrage bei Twitter angekommen ist, vollzieht Twitter das gleiche Ritual und generiert ebenfalls einen Authorization Header. Dann werden die beiden Header miteinander abgeglichen und solange beide Header gleich sind, wird die Anfrage gewährt und mit einer relevanten Antwort vom Server abgeschlossen.

Soviel zum groben Überblick über die Funktionsweise. Natürlich könnte ich die Dokumentation auch an einigen Stellen missverstanden haben, aber dann würde mein OAuth Modul wahrscheinlich auch nicht funktionieren.

Jedenfalls begab ich mich zunächst auf die Suche nach einem OAuth Modul. Ich dachte, dass es vielleicht schon jemanden gab, der mir die Arbeit bereits angenommen hatte. Und tatsächlich gibt es ein paar Lua OAuth Module. Alle sind jedoch abhängig von Bibliotheken, die man gewöhnlich über luarocks installiert und die in C programmiert worden sind. Diese Bibliotheken sind abhängig von der Plattform und lassen sich auch nicht in Codea einbinden.
Wie es aussah brauchte ich für mein Vorhaben Base64 und HMAC-SHA1. Den eigentlichen OAuth Code hätte ich mir aber selbst zusammenleiern müssen, denn in die kompilierten C Dateien konnte ich nicht hineinschauen und genau dort war der eigentliche Code versteckt.
Vielleicht hätte ich im Internet etwas in einer anderen Sprache finden und nach Lua übersetzen können, aber ich beschloss es allein zu versuchen. So schwer konnte es ja nicht sein?!

Also trug ich die Zutaten zusammen: das Sha1 Modul von Kikito, LuaSocket² - genauer die Funktion b64 aus der Mime Bibliothek - und die Dokumentation von Twitter. Schon nach ein paar Stunden hatte ich eine nicht funktionierende OAuth Routine.

Wie ich beim Debuggen gemerkt habe, hat Codea's Base64 Funktion irgendwie eine andere Signatur generiert, anders als alle anderen Generatoren die ich online ausprobiert habe. Rein optisch war die Signatur bis auf die letzten zwei Bytes korrekt, aber eben nicht komplett korrekt.

Ich beschloss jedenfalls mein OAuth Modul mit anderen Base64 und SHA1 Bibos³ zu testen, bevor ich auf die Fehlersuche in meiner eigenen OAuth Routine ginge. Und zufällig fand ich lockbox, eine Bibliothek mit allen möglichen Verschlüsselungsmethoden und Base64. Das einzige, was ich machen musste, ist es an Codea anzupassen und eine passende Bitwise Bibo zu finden.

Wie ich schon sagte, hat Codea bereits eigene Base64 und Bitwise Funktionen. Aber ich hatte ja damit zunächst falsche Ergebnisse geliefert bekommen, also legte ich nun wert darauf alle Bibos (zunächst) durch neue zu ersetzen. Lockbox kam da gerade recht. Eine schöne Sammlung an Funktionen für allerlei Aufgaben.

² LuaSocket ist in Codea integriert. Keine externe Bibliothek notwendig!
³ Bibo ist meine Abkürzung für Bibliothek.

Nachdem ich lockbox umgeschrieben hatte, ging es an den zweiten Test ... und alles lief zu meiner höchsten Zufriedenheit. Ich bekam sofort die Bestätigung, dass ich eine autorisierte HTTP Anfrage gemacht hatte.

Bis hierher hatte ich vorher generierte Tokens von Twitter benutzt, damit meine App an meiner Stelle Änderungen über meinen Twitter Account machen konnte. Heißt, nur mein Twitter Account konnte mit Hilfe des OAuth Modules HTTP Anfragen versenden. Ich wollte aber, dass mein OAuth Modul sich mit jedem beliebigen Twitter Account verbinden konnte. Und Dafür hat Twitter diese Login/App-Autorisierungsfenster die immer im Browser aufgehen, wenn man sich über Twitter zu einer App verbindet. Dabei loggt man sich ein und erlaubt der App Zugriff auf sein Twitter Konto.

Dabei unterscheidet Twitter zwischen verschiedenen 'Login-Möglichkeiten'. Die meisten leiten einen wieder zurück zur App, wenn man die App autorisiert hat. Aber eine Codea-App haben keine Webadresse zu der man im Anschluss springen könnte. In genau dort liegt das Problem, denn an diese Web-Adresse wir auch ein Token zu dem User-Account angehängt, den die App für die OAuth Routine benötigt. Lange Rede, kurzer Sinn: da ich keine Callback-URL habe, kann ich auch keinen Token anfordern.


Glücklicherweise gibt es eine einzige Möglichkeit auch ohne Callback-URL's zu arbeiten. Man loggt sich bei Twitter ein, autorisiert die App und bekommt einen PIN angezeigt. Anschließend geht man eigenständig zurück zur App und gibt dort den PIN ein. Durch diesen PIN kommt man schließlich an den User Token, den man für das OAuth Modul benötigt.

Das ganze Nebenprojekt hat mich etwa 12 Stunden Arbeitszeit gekostet. Eigentlich hat es sogar echt Spaß gemacht! Und nun kann Codea sich endlich mit Twitter verbinden und zusammenarbeiten. Man kann z.B. Tweets posten, löschen oder durchsuchen. Wenn jemand es wollte, könnte er mit diesem Modul eine Art TweetDeck App nachbauen. Aber vielleicht findet jemand auch eine andere Verwendung dafür...

Installation

Folgende Schritte sind nötig:

  1. Zuerst lade dir lockbox herunter und speichere es in deiner Dropbox im Codea-Ordner ab.
    Theoretisch könntest du den ganzen Quellcode auch direkt in Codea importieren, aber so viele Tabs würde dich nur stören, daher legst du es in deiner Dropbox ab. Du wirst es später per require "lockbox" in Codea laden.

  2. Erstelle ein neues Codea Projekt, oder öffne ein vorhandenes.
    Kopie zumindest den Inhalt aus der twitter.lua Datei (aus diesem Repository) und füge es in ein neues Tab in deinem Codea Projekt ein.
    In der Main.lua Datei ist nur ein Anwendungsbeispiel.

  3. Jetzt brauchst du deinen Twitter Account. Erstelle dir einen, wenn du keinen hast.
    Gehe zu http://apps.twitter.com, logge dich ein und registriere eine neue App.
    Jede App muss bei Twitter registriert werden, denn für eine Zugriffsanfrage benötigt sie Tokens! Übrigens, du brauchst keine Callback URL!

  4. Nun kannst du festlegen welche Rechte deine App braucht und bei einem Benutzer erfragen soll.

  5. Kopiere nun die Tokens "Consumer Key" und "Consumer Secret" und füge sie in dein twitter Tab deines Codea Projekts ein.
    Optional, kannst du auch "Access Token" und "Access Token Secret" von Twitter generieren lassen und nach Codea kopieren. In diesem Fall wäre deine App automatisch an deinen Twitter Account gebunden. In den meisten Fällen würde ich empfehlen diesen Schritt einfach auszulassen.

Probieren

Nun kannst du deine App starten. Wenn du den Inhalt der Main.lua Datei kopiert hast, wird deine Codea-App versuchen eine Anfrage an Twitter zu senden, um ein Tweet aus der Home-Timeline auszulesen. Wenn du den optionalen Schritt, wie angeraten, ignoriert hast, wird deine App als nächstes Versuchen sich zu einem Twitter Nutzer zu verbinden. Ein Fenster geht auf, dort kannst du dich einloggen und der App Zugriffsrechte erteilen. Dann wird ein PIN angezeigt, den du kopieren solltest. Klicke auf "Done", um das Browser-Fenster wieder zu schließen und füge deinen PIN in das Text-Feld ein. Klicke auf "twitter_connect". Nun solltest du einen Tweet auf dem Bildschirm ausgegeben bekommen.

  • twitter.check() prüft ob du autorisiert bist. Andernfalls wird es versuchen dich automatisch zu autorisieren, indem twitter.authenticate() aufgerufen wird.
  • twitter.authenticate() versucht die App zu einem Twitter zu verbinden und "Access Token" und "Access Token Secret" zu erfragen.
  • twitter.request(method, url, parameters, callback_success, callback_failure) ist die Haupt-Methode zum Arbeiten mit Twitter's REST API's.



Solltest du Fragen haben oder Hilfe bei der Installation benötigen, kannst du mich gern in der entsprechenden Forum Diskussion fragen, hier in den Kommentaren ansprechen oder per e-Mail kontaktieren.