Androidはワンツーパンチ 三歩進んで二歩下がる

プログラミングやどうでもいい話

Facebookの有効期限の長いユーザーアクセストークンを取得する

developers.facebook.com

このエントリーではFacebookのアクセストークンのうちユーザーアクセストークンについてのみ扱います。
なおこの情報は2015/09/29に書いたものですので、Facebookの仕様変更により参考にならなくなっている可能性がありますのでご注意くださいませ。graph APIのバージョンはv2.4になります。
おかしな点がありましたら遠慮なくお知らせくださいませ。


FacebookでWebクライアントからログインダイアログを通じてユーザーがログイン、アクセス権限の許可をするとアクセストークンが取得できます。
有効期限は短く、約1〜2時間で切れます。
これとは別に有効期限の長いアクセストークンも存在し約60日の期間有効です。
AndroidiOSSDKで取得したアクセストークンはデフォルトで有効期限の長いものになります。

アクセストークンの寿命は警告なしで変わるかもしれないのでこの期間をあてにするべきではありません。
次のページにあるようにトークンが期限切れの場合の実装をしておくべきでしょう。

エラーをハンドリングする


下記に述べるAPIを使うことによって有効期限の短いユーザーアクセストークンを有効期限の長いユーザーアクセストークンに変換することができます。

なお、アクセストークンの期限を調べるにはそれ用のAPIもありますが、
アクセストークンデバッガを利用すると便利です。



通常の有効期限の長いアクセストークンの取得方法

変更のシーケンスはこの図のようになります。

https://scontent.xx.fbcdn.net/hphotos-xfa1/t39.2178-6/851576_1401207796761754_1304362567_n.png

1.Webクライアントがログインダイアログで有効期限の短いアクセストークンを取得

2.あなたのサーバーにアクセストークンを送信

3.あなたのサーバーからアクセストークンにApp IDとAppシークレットを加えFacebookに送信

4.Facebookが有効期限の長いアクセストークンを生成し返却

5.あなたのサーバーからクライアントに有効期限の長いトークンを送信

6.クライアントから(サーバーからでもよい)有効期限の長いアクセストークンを使用してGraph APIを実行

注意点としては、app secretがこのcallに含まれますので、クライアントからは実行せずサーバーから実行するようにしてください。
また変換用のアクセストークンは有効期間内のものにして下さい。

サーバーに送るパラメータなどはこのようになります。

GET /oauth/access_token?  
    grant_type=fb_exchange_token&           
    client_id={app-id}&
    client_secret={app-secret}&
    fb_exchange_token={short-lived-token} 

例えば次のようなアプリなら(ブログ用に一時的に作ったものでもう存在しないです)
アプリケーションID:878783778895290
アプリのシークレットキー:11f9cb4c3fa8d9bb8308061c7849f6a2

全体のURLはこのようになります。

https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token&client_id=878783778895290&client_secret=11f9cb4c3fa8d9bb8308061c7849f6a2&fb_exchange_token=ここに有効期限の短いアクセストークンを入れる

レスポンスはこのようになります。

access_token=CAAMfP8r5tboBAI09nQSriKEKMVBzHIoh2AEpuqWd2f2Vd0iEGgBVxxtB6DjTai0UxXpPx21axKc139QHGKk0ZBUv3k6eTyawMIPTjasMTtDWIZCF5SkTIkYFTYXAIRBZBhw78a6b6dp2m9To843p2TZBM1MWkae3SZAIn7c4HhZBk17FEXsXEPlEDuawntejkZD&expires=5183946

access_token=以下のアクセストークンは有効期限が約2ヶ月になっています。
上記の一連の作業はGraph ExplorerとAccessToken Debuggerを使って試すことが出来ます。
手前味噌で恐縮ですが、過去エントリーを参考にしてみてくださいませ。

sakura-bird1.hatenablog.com


変換後のトークンは使用しているSDKによりますが、
JavascriptSDKならFB.api()メソッドaccess_tokenパラメータを使用して保存するといいと思います。

よりセキュアなcallをするためにappsecret_proofというパラメータを利用できます。
利用方法は公式サイトをご覧ください。
Securing Graph API Requests - 参考資料 - 開発者向けFacebook







コード取得後有効期限の長いアクセストークンと交換する方法


同じユーザーが複数のWebクライアントからAPIをコールするにあたって、同じアクセストークンを使うべきではありません。
(例えば複数のコンピュータからログインした場合など)
サーバーに保存した期限の長いアクセストークンを使う代わりに、Facebookにコードを生成させて各クライアント毎に違うアクセストークンを生成させる方法があります。

1.ユーザー名とパスワードのような独自の認証システムを持っている
2.サーバーにFacebookの期限の長いアクセストークンを保存している
(ブラウザやモバイルアプリなどの別のクライアントからのcallに使用する)
3.全てのクライアントからAPIをコールする

もしこのようなアプリの場合、Facebookの自動スパムシステムの引き金になるのを防ぐべく
次のような処理をします。
最終的に各クライアントが独自の有効期限の長いアクセストークンを持っていることになります。

1.あなたのサーバーからアクセストークンをFacebookサーバーに送ってコードを取得する
(既に有効期限の長いアクセストークンを取得している前提です。)

2.あなたのサーバーからクライアントにコードを送信する

3.クライアントはFacebookサーバーにコードを送って有効期限の長いアクセストークンを交換する

4.クライアントはストーリーやクエリデータを投稿するのに有効期限の長いトークンを使用できる

変更のシーケンスはこの図のようになります。

https://scontent.xx.fbcdn.net/hphotos-xfa1/t39.2178-6/851584_503291546407012_1005168000_n.png

1.あなたのサーバーからアクセストークンをFacebookサーバーに送ってコードを取得する

サーバーに送るパラメータなどはこのような形式になります。

https://graph.facebook.com/oauth/client_code?access_token=...&client_secret=...&redirect_uri=...&client_id=...


リダイレクトURLというのは
デベロッパーコンソールのMy Apps > アプリを選ぶ > 設定 > Website > Site URL
に設定したURLを指定します。

client_idはアプリケーションID
client_secretはアプリのシークレットキーを指定します。


レスポンスはこのようになります。

{"code":"AQBpFLvhZFkZrHNJf9GiLPmpCRlbjv0EweEqYXCnES5mxBkWOZ0pwHiWZcRY4meZVed7UuJTl3WkajxuVmg2ckORkPcmRLeivE1dRLXtK-t-EMm5AI8Lp958QLU-uXB6FMahfmnii00FnKiqSDNdzc7nyUN5zTONMIsis_MqsnhzteV9L9eGi9MnIBz0Qcflfq7iQfn_sq_8Y-uEVhpQbdeO3Ez77q7JJwpePVGL7WfOLwpOe9vgKdg1b4USNQbEx08necyxaDsnyqQbbRNa19xwWTzIASHgLWXk6ZMiyE85kIN1Dxz8uscbkT-WANIVhn-n_15E1gSpYw_lKlYY0Ldg2EgoLxLYRAmeD3RKdYwLLA"}

2.あなたのサーバーからクライアントにコードを送信する

1.で取得したcodeをクライアントに送ります。

3.クライアントはFacebookサーバーにコードを送って有効期限の長いアクセストークンを交換する

サーバーに送るパラメータなどはこのような形式になります。

https://graph.facebook.com/oauth/access_token?code=...&client_id=...&redirect_uri=...&machine_id= ...

machine_idというのはクライアント毎にFacebookサーバーが発行するものです。当然初回は指定する必要はありません。
次回からセットします。


レスポンスはこのようになります。

{"access_token":"CAAMfP8r5tboBAPSF4wvPR3dFdSdAFcClkM4yn0HwHKLU3sBWjKJAaNrYOhpmuMZA9p5o93dqUgSWTVeo1xZBVTno74kzl1r94qX3mu4jI1dd7QSc7jtCAvw4ZB91LZBwdsdu08vDiAU148ZCVmwW848WnG1ljSSs41mWYq1f8apGlaOfdDdeJczATpvYyTY0ZD","machine_id":"XVbxVah5bqsimnKHKHWs5o3z","expires_in":5177575}

有効期限の長いアクセストークンが返ってきました。