アジョブジ星通信

進捗が出た頃に更新されるブログ。

TwitterのOAuthバグを攻略

f:id:azyobuzin:20150418230034p:plain

TwitterAPI がクソであることは、数年前から既知の事実でしたが、まさか OAuth の仕様すら無視しているとは思ってもいませんでした。というのが 1 月あたりの話ですが、比較できるコードが書けたのでブログに書きます。

人類史上最悪のコミット

まずはこちらをご覧ください。

このコミットは

を受けて生まれた産物ですが、かなり強引なことをしました。ええ、それはもう、ね?

何が起こっていたのか

最初は誰もが

.NET 4.5 から Uri クラスが : を何故かアンエスケープしてしまう仕様になったせいで、 Twitter サーバーがエスケープされてないからエラーにしてる。

そう思っていました。ですが、現実はそんなに甘くなかった。実際には

Twitter サーバーは URI のクエリ部分や、リクエストボディをアンエスケープ→再エスケープせず、そのまま OAuth のシグネチャ作成に使用するため、クライアントでは : はエスケープされた状態でシグネチャ作成をしているが Twitter サーバーでは : のままシグネチャを作成するからエラーになる。

という大変悲惨なことになっていました。

というわけで

azyobuzin による OAuth 実装最新作です。

var handler = new TwitterOAuthHttpMessageHandler(new HttpClientHandler())
{
    ConsumerKey = "",
    ConsumerSecret = "",
    OAuthToken = "",
    OAuthTokenSecret = ""
};
var client = new HttpClient(handler);
// 「from:azyobuzin ねむい」で検索
var res = await client.GetAsync("https://api.twitter.com/1.1/search/tweets.json?q=from:azyobuzin%20%E3%81%AD%E3%82%80%E3%81%84");

この例では、 TwitterOAuthHttpMessageHandler では動きますが、 OAuthHttpMessageHandler では 401 が返って来ます。

Twitter 以外はどうなの?

試しに Tumblr で同じことをやってみましたが、 OAuthHttpMessageHandler でのみ動きました。

まとめ

Twitter はクソ。でも今から仕様変えられたらそれはそれで困る(きっと中の人も気づいてるけどそうしてるんじゃないかな…)。

追記: DotNetOpenAuth は OAuthHttpMessageHandler 側の実装です。