masat999's posterous

iアプリでTwitterのOAuth認証を実装する

PHP や Ruby での OAuth 認証については幾つも情報がありますが、iアプリで OAuth 認証をやった話題はとんと見かけません。ドコモマーケットで個人がDXアプリを提供することもできるようになった今、ログを兼ねてどのように実装したか残しておきたいと思います。

(1) ライブラリの入手

J2ME で使える OAuth ライブラリですが、次の2種を検討しました。   

・ Twitter API ME (http://kenai.com/projects/twitterapime/pages/Home)
・ j2me-oauth (https://github.com/simonpk/j2me-oauth) ←今回採用したのはこちら

Twitter API ME は Twitter に特化したライブラリで、Twitter Dev のどこかでも推奨されているような記述がありましたが、結論から言いますと、iアプリでは外部jar の組み込みが簡単にできない仕様から諦めました。少なくともそのまま使うことはできません。(ソースから iアプリライブラリを生成する手順が必要です。面倒、っつーか Write once, Run anyware じゃないのかよ、と…。)

とりあえず今は認証だけどうにかやってみたかったので、少なくとも j2me-oauth で十分です。とはいえこちらも jar をそのまま使うことはできませんので、ソースを再利用して実装しました。

特に Doja/Star では javax.microedition.io パッケージにあるはずのクラスの一部がドコモ独自パッケージにあったり、j2me-oauth 自体にもバグがあったりと、そのまま使えるとまではいきませんでしたが、対処できる範疇でした。access_token で渡すべき oauth_verifier パラメータは自分で追加するなど、多少の修正は覚悟しておきましょう。

もしライブラリを使わずに自力で全部実装するなら、signiture の生成(Twitter は HMAC-SHA1 のみ。書けるスキルがあるならライブラリの再利用の方がよほど楽だと思います)のところが特に大変だと思われます。あとは決まった宛先にパラメータつなげて送受信するだけ、と言ってしまえばそれまでなので。iアプリでは「それまで」のところがまた面倒なんですが、それはまた別の話。

(2) OAuthの認証フローについて

検索には色々ヒットしますが、頭の悪い私には難解すぎて意味不明…。認証フローについて結局一番よく理解できたのが以下の Twitter Dev の情報でした。 xAuth なら 3. 4. の代わりに id, password を渡せば良いはずだと思いますが、xAuth は個別にリクエストして承認してもらえないと使えませんし、Twitter 自体も推奨はしていない方法です。となれば、純粋な OAuth 認証で解決する方法は把握しておきたいものです。

Authenticating Requests with OAuth
Overview of "Sign in with Twitter"

(3) 実装の手順

流れは以下の通りです。xAuth を使わない限り、3. 4. のステップでブラウザアクセスが必要になることは覚悟しておく必要があります。 3. のレスポンスから hidden パラメータ諸共引っこ抜いてアプリで実装できなくもないですが、Twitter の利用規約上それが許されているかどうかまでは調べていないのでやってません。

1. https://api.twitter.com/oauth/request_token から request token を取得する。
2. 取得した request token を保存する。
    * iアプリならスクラッチパッド領域にでも保存してしまえばよろしいかと。
3. https://api.twitter.com/oauth/authenticate にブラウザでアクセスして承認、画面に表示される PIN を入手する。
4. アプリに戻り PIN を入力させる。
    * これも次回以降のアクセスで必要なのでスクラッチパッドですね。
    * request token が変わってしまったら PIN も再取得なので注意。
5. https://api.twitter.com/oauth/access_token に 2. の token と 4. の PIN を渡す。
    * レスポンスから user_id と screen_name ももらえます。
6. OAuth 認証が通れば、statuses/home_timeline, statuses/update などの API が呼べるようになります。

(4) サンプル

詳細出せないので余計に分かりにくいかもしれませんが、ソースはだいたいこんな感じになります。ご参考になれば幸いです。

Consumer consumer = new Consumer(CONSUMER_KEY, CONSUMER_SECRET, "oob");
consumer.setSignatureMethod("HMAC-SHA1");
try {
    String token = null;
    String pin = null;
    if (ScratchPadManager.isSaved(0)) {
        token = ScratchPadManager.loadString(0);
        RequestToken rToken = new RequestToken(token, CONSUMER_SECRET);
        rToken.setAuthorized(true);
        // pin (=oauth_verifier) has to be set.
        AccessToken aToken = consumer.getAccessToken("https://api.twitter.com/oauth/access_token", rToken);
    }
    if (token == null || token.equals("")) {
        RequestToken rToken = consumer.getRequestToken("https://api.twitter.com/oauth/request_token");
        ScratchPadManager.save(0, rToken.getToken());
        Launcher.launch(Launcher.LAUNCH_BROWSER,
            new String[] {"https://api.twitter.com/oauth/authenticate?oauth_token=" + rToken.getToken()});
    }
} catch (OAuthServiceProviderException e) {
    e.printStackTrace();
} catch (BadTokenStateException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

Filed under: doja+star
1 comments
Dec 22, 2010
masat999 said...
(3)に書いたレスポンスを引っこ抜く方法については”そもそも”論がありました。補足しときますと、
OAuthの考え方は「認証はTwitterがやる」という前提において id, password をアプリで入力しないことがメリットであって、xAuth が何故推奨されないのかというと、アプリで id, password を入力しなければならず、セキュリティ上の懸念が生じることになるからです。
そう考えた場合、せっかくOAuthで認証しようとしているのに、アプリで id, password を入力させるような仕組みを持つこと自体が本末転倒になりかねないという考え方ができます。
面倒に見えてもアクションは一度だけで済みますし、何よりセキュリティリスクを抱かせないのは、境界を明確に分けておくことの意義も十分あるように思います。

ガラケーの多くの機種が端末IDを垂れ流しまくっている事実は、もっと懸念しなければいけないセキュリティリスクなんだと思うのですけどね。(悪用されたらTwitterだけの話どころじゃ済まないので。

Leave a comment...

To Posterous, Love Metalab
Web Toolbar by Wibiya