Facebook Platformは、ユーザ認証と権限の認可にはOAuth 2.0 protocolを用います。ウェブサイト上、モバイル、デスクトップなどで扱えるように、多くの異なるOAuthのフローをサポートしています。このドキュメントでは、Facebook Platformが使っているそれら各フローの仕組みを解説します。ここでのサンプルには、サーバサイドにはPHP、クライアントサイドにはHTML/JavaScriptを用いています。これらのサンプルは明解なので、他の言語へ簡単に置き換えることができます。
目次:
User Login
Facebook Platformは、ユーザのログイン用に2つのOAuth2.0のフローを用意しています。server-side (仕様上でauthentication code flowと呼ばれている部分です) と、client-side(implicit flowと呼ばれます)です。サーバサイドのフローは、あなたのウェブサーバからGraph APIを使う必要のあるときならいつでも使えます。クライアントサイドのフローは、ブラウザ上でJavaScriptによって、もしくはモバイルやデスクトップのアプリから、Graph APIを用いるときに用います。
用いるフローに関わらず、FacebookのOAuth2.0の実装は3つのステップから成り立ちます。user authentication, app authorization, app authenticationです。user authenticationで、ユーザが誰であるのかを保証します。app authorizationは、ユーザがアプリに対してどの情報を提供するのか理解していることが保証されます。app authenticationは、ユーザが他の誰かにではなく、あなたのアプリに対して情報を提供することが保証されます。これらの手順が完了すると、アプリはuser access tokenを与えられ、ユーザの情報にアクセスしたりユーザの代理として行動できるようになります。
Server-side Flow
user authenticationとapp authorizationは、ユーザをOAuth Dialogへとリダイレクトするのと同じタイミングで同時に行われます。このダイアログを開くときには、Developer Appでアプリを作成した時に与えられたapp id(cliend_idパラメータ)と、完了後のリダイレクト先(redirect_uriパラメータ)を渡さなくてはなりません。redirect_uriはDeveloper AppのWeb siteタブで設定したSite URLのドメインと同じドメインでなくてはなりません。
https://www.facebook.com/dialog/oauth?
client_id=YOUR_APP_ID&redirect_uri=YOUR_URL
ユーザがログイン済みだった場合、ユーザのブラウザ上に保持されているクッキーでログイン状態をチェックし、ユーザ認証します。ユーザが未ログインだった場合、ログインを促されます。
ユーザ認証に成功すると、アプリに対して権限を認可するよう、OAuthダイアログがユーザに促します。
デフォルトで、ユーザはアプリに対してbasic informationへのアクセスを認可するように求められます。これらは公開されていたり、デフォルトでFacebook上で公開されている情報です。この基本情報以上の情報が必要な場合は、必要に応じたパーミッションを得る必要があります。これは、OAuth Dialogリクエストの際にカンマ区切りのパーミッションのリストをscopeパラメータに指定することで実現できます。以下のサンプルが、ユーザのemailとnews feedへのアクセスを求める方法を示しています。
https://www.facebook.com/dialog/oauth?
client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&scope=email,read_stream
上記の結果、ログイン後に以下のようなダイアログが開きます。
パーミッションの一覧はpermissions reference.で見る事ができます。求めるパーミッションの数とそれらを承認するユーザ数には、強い反比例の関係があります。多くのパーミッションを求めるほどそれを承認するユーザ数は減ってしまいますので、本当に必要なものだけを選ぶようお勧めします。
ユーザがDon't Allowを押した場合、アプリは認可されません。OAuth DialogはHTTPステータスコード302でredirect_uriパラメータで指定されたURLへ、以下のようなエラー情報とともにリダイレクトされます。
http://YOUR_URL?error_reason=user_denied&
error=access_denied&error_description=The+user+denied+your+request.
ユーザがAllowを押した場合、アプリに対して権限が認可されます。OAuth DialogはHTTPステータスコード302でredirect_uriパラメータに指定されたURLへ、以下のようなauthorization codeとともにリダイレクトされます。
http://YOUR_URL?code=A_CODE_GENERATED_BY_SERVER
このコードを用いることで、次のステップ(app authentication)へと進んでAPI利用に必要なaccess tokenを得ることができます。
アプリを認証するため、Graph APIの https://graph.facebook.com/oauth/access_tokenに対してauthorization codeとapp secretを送る必要があります。app secretは
Developer Appで得ることができますが、誰かと共有したり、公開するコード上に書いてはいけません(そのような場合にはクライアントサイドのフローを使うべきです)。
https://graph.facebook.com/oauth/access_token?
client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&
client_secret=YOUR_APP_SECRET&code=THE_CODE_FROM_ABOVE
アプリが認証されてauthorization codeが正しいものと分かれば、authorizationサーバはaccess tokenを返します。
access token(access_tokenパラメータ)の他に、そのトークンが無効となるまでの秒数(expiresパラメータ)が渡されます。トークンが無効になると、上記のプロセスをもう一度実行して新しいaccess_tokenを得る必要がありますが、すでにアプリを認可していれば、また同じことをするように促されることはありません。ずっと有効なaccess tokenが必要な場合(ユーザがアプリを使っていない時にユーザの代理として何かする時など)は、offline_accessパーミッションをリクエストすることができます。
アプリを認可するのに問題がある場合、authorizationサーバはHTTPステータスコード400で以下のようなエラーをレスポンスで返します。
{
"error": {
"type": "OAuthException",
"message": "Error validating verification code."
}
}
以下のPHPサンプルはサーバサイドのフローの例を示しています。<?php
$app_id = YOUR_APP_ID;
$app_secret = "YOUR_APP_SECRET";
$my_url = "YOUR_URL";
$code = $_REQUEST["code"];
if(empty($code)) {
$dialog_url = "http://www.facebook.com/dialog/oauth?client_id="
. $app_id . "&redirect_uri=" . urlencode($my_url);
echo("<script> top.location.href='" . $dialog_url . "'</script>");
}
$token_url = "https://graph.facebook.com/oauth/access_token?client_id="
. $app_id . "&redirect_uri=" . urlencode($my_url) . "&client_secret="
. $app_secret . "&code=" . $code;
$access_token = file_get_contents($token_url);
$graph_url = "https://graph.facebook.com/me?" . $access_token;
$user = json_decode(file_get_contents($graph_url));
echo("Hello " . $user->name);
?>
Client-side Flow
クライアントサイドのフローもOAuth Dialogでuser authenticationとapp authorizationを行います。唯一の違いは、response_type=tokenを指定しなくてはいけないことです。
https://www.facebook.com/dialog/oauth?
client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&response_type=token
サーバサイドと同じく、scopeパラメータを指定することで追加のパーミッションをリクエストすることができます。
https://www.facebook.com/dialog/oauth?
client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&scope=email,read_stream&
response_type=token
ユーザ認証し、アプリの権限が認可されると、redirect_uriで指定したURLへリダイレクトされます。サーバサイドのフローのようにcodeパラメータでauthorization codeが渡されることはなく、URIフラグメント(#access_token)として渡されます。
http://YOUR_URL#access_token=166942940015970%7C2.sa0&expires_in=64090
URIフラグメントとしてaccess tokenが渡されるので、クライアントサイドのコード(ブラウザ上で実行されるJavaScriptなど)のみがトークンを受け取ることができます。app authenticationは、redirect_uriのドメインがDeveloper AppのSite URLに指定したドメインと同じものであるとチェックして行います。
以下のHTML/JavaScriptの例は、クライアントサイドのフローを示しています。
<html>
<head>
<title>Client Flow Example</title>
</head>
<body>
<script>
var appId = "YOUR_APP_ID";
if(window.location.hash.length == 0)
{
url = "https://www.facebook.com/dialog/oauth?client_id=" +
appId + "&redirect_uri=" + window.location +
"&response_type=token";
window.open(url);
} else {
accessToken = window.location.hash.substring(1);
graphUrl = "https://graph.facebook.com/me?" + accessToken +
"&callback=displayUser"
//use JSON-P to call the graph
var script = document.createElement("script");
script.src = graphUrl;
document.body.appendChild(script);
}
function displayUser(user) {
userName.innerText = user.name;
}
</script>
<p id="userName"></p>
</body>
</html>
Using the Access Token
有効なaccess tokenがあれば、Graph API(とLegacy REST API)のリクエストにaccess_tokenパラメータとして渡すことでGraph APIを利用することができます。
https://graph.facebook.com/me?access_token=ACCESS_TOKEN
ユーザがパスワードを変更すると、access tokenは無効になります。また、ユーザがApp Dashboardからアプリの権限認可を取り消した場合、Graph APIはHTTPステータスコード400で以下のようなレスポンスを返します。
{
"error": {
"type": "OAuthException",
"message": "Error validating access token."
}
}
再度適切なフローを実行することで新しいaccess tokenを得ることができます。App Deauthorization
ユーザがApp Dashboardからアプリを取り除いてしまったり、News Feedでアプリをブロックすると、アプリ側はDeveloper Appで指定する Deauthorize Callback URLから通知されます。アプリを取り除くとき、HTTP POSTリクエストでsigned_requestというパラメータが送られ、デコードすると削除したユーザのuser_idを含むJSONオブジェクトになります。このリクエストではユーザのaccess tokenは渡されず、また、この時点で該当ユーザのaccess tokenは全て無効になります。
App Login
User Loginだけでなく、Facebook PlatformはOAuth2.0 Credential flowを使ったApp Loginもサポートしています。App Loginは、アプリの管理者として様々な情報を得ることを可能にします。たとえば、insightsの統計情報へのリクエストを認可したりです。アプリ用のaccess tokenを要するGraph APIの利用に関しては、APIリファレンスに明記されています。
アプリ用のアクセストークンは、https://graph.facebook.com/oauth/access_tokenに対して、アプリidとアプリのsecret key、それからgrant_typeにclient_credentialsを指定したものを渡して得られます。アプリのIDとsecret keyは、
Developer Appでアプリを作成した時に生成されます。
https://graph.facebook.com/oauth/access_token?
client_id=YOUR_APP_ID&client_secret=YOUR_APP_SECRET&
grant_type=client_credentials
HTTP GETリクエストを上記URLへ送ると、ボディにaccess_tokenが入った状態でレスポンスが返されます。
Graph APIの特定の分野(例えばApp Insightsなど)へアクセスするには、このアクセストークンを用います。
https://graph.facebook.com/YOUR_APP_ID/insights?
access_token=TOKEN_FROM_ABOVE
Page Login
Facebook Pageは、ユーザログインやアプリログインとは若干違うフローを用います。ページには一人もしくはそれ以上の管理者がいます。これら全部の管理者が管理を行えるようにするには、ユーザがmanage_pagesパーミッションを与える必要があります。https://www.facebook.com/dialog/oauth?
client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&scope=manage_pages&
response_type=token
管理者がこのパーミッションを与えると、User Graph APIのaccount connectionにアクセスできるようになります。
https://graph.facebook.com/me/accounts?access_token=TOKEN_FROM_ABOVE
このconnectionは、該当ユーザが管理者となっている全ページの詳細と、それぞれのページのアクセストークンのリストを返します。
任意のページ用のアクセストークンを用いることで、ユーザの代理としてそのページの管理行動をとることができます。
App Types
Facebook Platformは、Websites, Apps on Facebook.com, Mobile,Desktop Appsなど異なる種類のアプリに対し、上記のように様々なOAuthフローを提供しています。Websites
Website Getting Started Guide では、JavaScript SDK and Login Social Pluginを用いてwebサイトにユーザログインを追加する方法の概略を説明しています。Apps on Facebook.com
Apps on Facebook.com Getting Started Guideでは、Facebook上のアプリでユーザログインを扱う方法を解説しています。Mobile Apps
Mobile App Getting Started Guideでは、mobile SDKでOAuth Dialogを用いてモバイル端末でユーザログインを使う方法を紹介しています。Desktop Apps
これらOAuth2.0の実装は、デスクトップアプリのサポートを含んでいません。しかし、あなたの作るデスクトップアプリにwebブラウザを組み込める(.NET, AIR, Cocoa などほとんどのデスクトップフレームワークはサポートしています)のなら、client-side flowを一部改変(redirect_uri)して使うことができます。デスクトップアプリに対してwebサーバをホストしてサイトURLを持たせる代わりに、http://www.facebook.com/connect/login_success.html
というURLを提供しています。
- webブラウザを組み込んでOAuth Dialog(
https://www.facebook.com/dialog/oauth
)を読み込み、client-side flow(response_type=tokenなど)を使います
https://www.facebook.com/dialog/oauth?
client_id=YOUR_APP_ID&
redirect_uri=http://www.facebook.com/connect/login_success.html
- ユーザがアプリに対して権限を認可すると、ユーザはredirect_uriへとURIフラグメント中にアクセストークンを持ってリダイレクトされます。
http://www.facebook.com/connect/login_success.html#access_token=...
- このリダイレクトを受け取ったらURIからアクセストークンを読みこみます
Security Considerations
Cross Site Request Forgery (CSRF)
Cross site request forgeryは、信頼されている(認証/認可した状態)ユーザが知らない間にwebサイト上で行動をとらされる攻撃です。これを防ぐため、stateパラメータでidentifierを渡し、それをレスポンスと一致するかチェックすべきです。Facebookユーザログインを実装する全てのアプリが、この方法を用いてCSRFに対応することを強く勧めます。