まえおき
Rocket.Chat というMeteorフレームワークを使った代表的なチャットアプリがあります。
Slackを自前の鯖に建てたい、みたいな人にはちょうどいいアプリです。
で、
- こいつをAndroidから使えるようになったらいいなー
- オープンソースやってます( ー`дー´)キリッといえる何かをやりたいなぁ
ということで、 Rocket.Chat.Android ってのを頑張って作ってみてます。
GitHubのOAuth使いたい!と思って、実装をこころみたところ、なかなか一筋縄ではいかない感じだったので、ちょっとメモっておきます。
Rocket.ChatのGitHub OAuthのフロー
1. サーバが対応してくれている場合のみ、WebSocketからGitHubのクライアントIDが流れてくる
send: {"msg":"sub","id":"hogehogehogeho1","name":"meteor.loginServiceConfiguration","params":[]}
receive: {"msg":"added","collection":"meteor_accounts_loginServiceConfiguration","id":"JMBQZo25cKkcgkzNB","fields":{"service":"github","clientId":"886a7b2a1fb067b10d3a"}}
receiveは他にもTwitterとかFacebookとかGoogleとかも、対応してたら流れてきます。
2. stateを生成する
Meteorのソースをみてみたところ、以下の様な方法でstate(GitHubのOAuthのときに渡す乱数パラメータてきなやつ)を生成しているみたいです。
OAuth._stateParam = function (loginStyle, credentialToken, redirectUrl) {
var state = {
loginStyle: loginStyle,
credentialToken: credentialToken,
isCordova: Meteor.isCordova
};
if (loginStyle === 'redirect')
state.redirectUrl = redirectUrl || ('' + window.location);
// Encode base64 as not all login services URI-encode the state
// parameter when they pass it back to us.
// Use the 'base64' package here because 'btoa' isn't supported in IE8/9.
return Base64.encode(JSON.stringify(state));
};
こいつが若干やっかいで、
- 毎度違うものをわたさないといけない
- データの整合性は取れている必要がある
で、ちょっとloginStyleあたりのソースもあわせて読みつつ、
コンソールで↓のようにたたくことで生成できるっぽいことがわかりました。
echo '
var state = {
loginStyle: "popup",
credentialToken: "hogehogehogehogehogehoge"+(new Date()-0),
isCordova: true
};
console.log(JSON.stringify(state)); ' | node | base64
credentialTokenは、毎回違う値が渡せていれば、かなりてきとういいです。
3. GitHub APIをWebブラウザで開く
https://github.com/login/oauth/authorize?client_id=886a7b2a1fb067b10d3a&scope=user%3Aemail&redirect_uri=https://demo.rocket.chat/_oauth/github?close&state=eyJsb2dpblN0eWxlIjoicG9wdXAiLCJjcmVkZW50aWFsVG9rZW4iOiJob2dlaG9nc2Zzb2RpZmpkc2hvZ2UxNDQ4OTk1MjcyMjcxIiwiaXNDb3Jkb3ZhIjp0cnVlfQo=
こんなかんじの、ながーーいURLをブラウザで開いて、OAuth認証・認可をします。
(※ ユーザ操作がともないます)
パラメータをちょっとだけ整理すると、↓のようなかんじ。
key | value | 備考
-------------+----------------------------+--------------------------
client_id | 886a7b2a1fb067b10d3a | WebSocketから流れてきたやつ
redirect_uri | [host]/_oauth/github?close | ReadMeにかいてあった
scope | user:email |
state | eyJsb2dpblN.......Qo= |手順2で生成したやつ
4. リダイレクト先のWebページのHTMLを見る
認可が完了すると、白紙のWebページにとばされます。が、HTMLは書いてあって、
↓のようなコードがあります。
<div id="config" style="display:none;">{"setCredentialToken":true,"credentialToken":"hogehogsfsodifjdshoge1448994999884","credentialSecret":"-bK92Xpv9AMQA3VTdwSB94cF6paLIFVxH8OqWzr50wT","storagePrefix":"Meteor.oauth.credentialSecret-","isCordova":true}</div>
configのなかの、credentialTokenとcredentialSecretを使います
5. ログイン!
send:{"msg":"method","method":"login","params":[{"oauth":{"credentialToken":"hogehogsfsodifjdshoge1448995272271","credentialSecret":"juN7gw7FsLopboQpUnLW4Lz1MpCDCRnnaF9PuQQFtXS"}}],"id":"123sdfiuh3e"}
receive:{"msg":"added","collection":"users","id":"wffqrSXNojgMnuz8v","fields":{"emails":[{"address":"xxxxxxxxx@crowdworks.co.jp","verified":true}],"username":"YusukeIwaki"}}
receive:{"msg":"result","id":"123sdfiuh3e","result":{"id":"wffqrSXNojgMnuz8v","token":"YmebU............Q5n","tokenExpires":{"$date":1456771391735}}}
って感じで、tokenが得られたら成功です!
次回からはこのtokenを使えば、ブラウザを開く必要はありません。
おわりに(ひとりごと)
Rocket.Chatの手順で説明しましたが、Meteor使ってるアプリならコールバックURL以外は基本的な流れは一緒だと思います。
とはいえ、細かすぎてワケガワカラナイヨ って感じですね・・・
MeteorにGitHubログインのためのREST APIだれかつくって・・・