Rocket.Chat（Meteor）のGitHubログインをかなり無理やりAndroidのアプリからおこなう


## まえおき

[Rocket.Chat](https://github.com/RocketChat/Rocket.Chat) というMeteorフレームワークを使った代表的なチャットアプリがあります。
Slackを自前の鯖に建てたい、みたいな人にはちょうどいいアプリです。

で、

* こいつをAndroidから使えるようになったらいいなー
* オープンソースやってます( ｰ`дｰ´)ｷﾘｯといえる何かをやりたいなぁ

ということで、 [Rocket.Chat.Android](https://github.com/yi01/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のときに渡す乱数パラメータてきなやつ）を生成しているみたいです。

```javascript:meteor//packages/oauth/oauth_client.js
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あたりのソースもあわせて読みつつ、
コンソールで↓のようにたたくことで生成できるっぽいことがわかりました。

```bash:state生成
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](https://github.com/RocketChat/Rocket.Chat/wiki/OAuth-Provider-Configuration)にかいてあった
scope        | user:email                 | 
state        | eyJsb2dpblN.......Qo=     |手順２で生成したやつ



### 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だれかつくって・・・