ログインフローを手動で構築する

Windows 8などのネイティブデスクトップアプリ用のウェブビューや、完全にサーバー側のコードを使用するログインフローのように、FacebookのSDKを使用しないブラウザーベースのログインをウェブアプリやデスクトップアプリに実装したい場合、ブラウザーのリダイレクトを使って自分でログインフローを構築できます。このガイドでは、ログインフローの各ステップと、FacebookのSDKを使用せずにそれぞれを実装する方法を説明します。

デスクトップアプリでFacebookログインを使用するには、ログイン処理を実行するアプリ内にウェブブラウザー(ウェブビュー)を埋め込む必要があります。

ログインステータスの確認

FacebookのSDKを使用するアプリは、組み込み関数を使って、利用者がログインしたかどうかを確認できます。それ以外のすべてのアプリでは、利用者がいつログインしたかを保存する独自の方法を作成する必要があります。ログインしたことを示すものがない場合、ログアウトしている前提で進められます。利用者がログアウトしている場合、適切なタイミングで(ログインボタンをクリックしたときなど)、アプリによってログインダイアログにリダイレクトする必要があります。

利用者のログイン

利用者がアプリやFacebookにログインしていなくても、ログインダイアログを使い、両方にログインするプロンプトを出すことができます。利用者がFacebookにログインしていない場合は、最初にFacebookへのログイン、次にアプリへのログインを促すプロンプトが表示されます。これは自動的に検出されるため、この動作を有効にするために特別な設定は必要ありません。


ログインダイアログの呼び出しとリダイレクトURLの設定

アプリで、ログインダイアログを表示するエンドポイントへのリダイレクトを開始する必要があります。

https://www.facebook.com/v21.0/dialog/oauth?
  client_id={app-id}
  &redirect_uri={redirect-uri}
  &state={state-param}

このエンドポイントには次の必須パラメーターがあります。

  • client_id: アプリのID。アプリダッシュボードで確認できます。
  • redirect_uri: ログインする利用者のリダイレクト先のURL。このURLはログインダイアログからの応答をキャプチャします。これをデスクトップアプリ内のウェブビューで使用する場合、https://www.facebook.com/connect/login_success.htmlに設定してください。このURLがアプリに設定されているかは、アプリダッシュボードで確認できます。アプリダッシュボード左側のナビゲーションメニューの[製品]で、[Facebookログイン][設定]の順にクリックします。[クライアントOAuth設定]セクションで[有効なOAuthリダイレクトURI]を確認します。
  • state: リクエストとコールバック間の状態を維持するために、アプリで作成される文字列。このパラメーターはクロスサイトリクエストフォージェリを防ぐために使用する必要があり、変更されずにリダイレクトURIに返されます。

例えば、次のようなログインリクエストがあるとします。

https://www.facebook.com/v21.0/dialog/oauth?
  client_id={app-id}
  &redirect_uri={"https://www.domain.com/login"}
  &state={"{st=state123abc,ds=123456789}"}

リダイレクトURIは以下を使用して呼び出されます。

https://www.domain.com/login?state="{st=state123abc,ds=123456789}"
    

さらに、以下の任意のパラメーターもあります。

  • response_type: アプリに戻るリダイレクトが発生したときの応答データを、URLパラメーターとURLフラグメントのどちらに含めるかを決めます。どちらのタイプをアプリで使用するかについては、IDの確認セクションをご覧ください。次のいずれかを使用できます。
    • code。応答データはURLパラメーターとして含められ、codeパラメーター(各ログインリクエストに固有の暗号化文字列)が含まれます。このパラメーターを指定しない場合、これがデフォルトの動作になります。サーバーでトークンを処理する場合に非常に便利です。
    • token: 応答データはURLフラグメントとして含められ、アクセストークンが含まれます。デスクトップアプリはresponse_typeにこの設定を使用する必要があります。クライアントがトークンを処理する場合に非常に便利です。
    • code%20token。応答データはURLフラグメントとして含められ、アクセストークンとcodeパラメーターの両方が含まれます。
    • granted_scopes: ログイン時にユーザーがアプリに付与するアクセス許可すべてを、コンマ区切りリストで返します。他のresponse_type値と組み合わせることができます。tokenと組み合わせた場合、応答データはURLフラグメントとして含められ、それ以外の場合はURLパラメーターとして含められます。
  • scope: アプリの利用者にリクエストするアクセス許可の、コンマ区切りまたはスペース区切りのリスト。
Windows 8のアプリの場合

Windowsアプリのログインを構築する場合、redirect_uriとしてパッケージセキュリティ識別情報を使用できます。WebAuthenticationBroker.AuthenticateAsyncを呼び出してログインダイアログを起動し、ログインダイアログエンドポイントをrequestUriとして使用します。JavaScriptの例を示します。

var requestUri = new Windows.Foundation.Uri(
  "https://www.facebook.com/v21.0/dialog/oauth?
    client_id={app-id}
    &display=popup
    &response_type=token
    &redirect_uri=ms-app://{package-security-identifier}");

Windows.Security.Authentication.Web.WebAuthenticationBroker.authenticateAsync(
  options,
  requestUri)
  .done(function (result) {
    // Handle the response from the Login Dialog
  }
);

成功した場合は制御フローがアクセストークンとともにアプリに返され、失敗した場合はエラーが返されます。

ログインダイアログの応答の処理

ログインフローのこの時点で、利用者にはログインダイアログが表示され、キャンセルするか利用者のデータへのアクセスをアプリに許可するかを選択できます。

アプリの利用者がログインダイアログでOKを選択すると、公開プロフィールや友達リストへのアクセスと、アプリがリクエストするその他のアクセス許可を付与することになります。

いずれの場合もブラウザーはアプリに戻り、利用者が接続またはキャンセルしたことを示す応答データが返されます。アプリが前述のリダイレクト方法を使用する場合、アプリが戻すredirect_uriの末尾に、(選択したresponse_typeに応じて) URLパラメーターまたはURLフラグメントが追加されます。これをキャプチャする必要があります。

ウェブアプリではコード言語のさまざまな組み合わせを使用できるため、このガイドで具体的な例は取り上げません。現代語の大半では、次のようなURL解析が可能です。

クライアント側のJavaScriptは、URLフラグメント(jQuery BBQなど)をキャプチャできます。一方、クライアント側とサーバー側のコードはどちらもURLパラメーター(PHPの$_GET、jQuery BBQのjQuery.deparam、Node.jsのquerystring.parse、Pythonのurlparseなど)をキャプチャできます。Microsoftは、"オンラインプロバイダー" (ここではFacebook)に接続するWindows 8アプリ向けのガイドとサンプルコードを提供しています。

デスクトップアプリを使用してログインすると、Facebookは利用者を前述のredirect_uriにリダイレクトし、アクセストークンと他のメタデータ(トークンの期限など)をURIフラグメントに挿入します。

https://www.facebook.com/connect/login_success.html#
    access_token=ACCESS_TOKEN...

アプリはこのリダイレクトを検出し、使用しているOSと開発フレームワークで提供されるメカニズムを利用して、URIからアクセストークンを読み取る必要があります。その後は、アクセストークンの検査のステップにそのまま進むことができます。


ログインがキャンセルされた場合

アプリの利用者がログインダイアログでキャンセルをクリックした場合、以下のようにリダイレクトされます。

YOUR_REDIRECT_URI?
 error_reason=user_denied
 &error=access_denied
 &error_description=Permissions+error.

利用者がログインを拒否した場合のアプリの対処方法については、不足しているアクセス許可の処理をご覧ください。

IDの確認

このリダイレクトフローでは、ブラウザーがログインダイアログからアプリのURLにリダイレクトされるため、トラフィックは架空のフラグメントまたはパラメーターでこのURLに直接アクセスすることになります。アプリがこれらを有効なパラメーターであることを前提とすると、この架空のデータがアプリにより悪用される可能性があります。そのため、アクセストークンを生成する前に、アプリの利用者が応答データの対象と同じ人物であることを確認する必要があります。IDの確認は、前述の手順で受け取ったresponse_typeに応じた方法で行われます。

  • codeを受け取った場合、エンドポイントを使用してアクセストークンを交換する必要があります。app secretが関係するので、呼び出しはサーバー間で行わなければなりません(app secretがクライアントコードに含まれないようにしてください)。
  • tokenを受け取った場合、検証が必要です。トークンがどのアプリで誰に生成されたかを示す、検査エンドポイントに対する呼び出しを行っていください。このAPI呼び出しではアプリアクセストークンを使用する必要があるため、クライアントからこの呼び出しを行わないでください。app secretを安全に保管できるサーバーからこの呼び出しを行ってください。
  • codetokenの両方を受け取ったら、両方のステップを実行する必要があります。

独自のstateパラメーターを生成してログインリクエストで使用し、CSRF保護を提供することもできます。

コードをアクセストークンと交換する

アクセストークンを取得するには、以下のOAuthエンドポイントに対してHTTP GETリクエストを実行します。

GET https://graph.facebook.com/v21.0/oauth/access_token?
   client_id={app-id}
   &redirect_uri={redirect-uri}
   &client_secret={app-secret}
   &code={code-parameter}

このエンドポイントには次の必須パラメーターがあります。

  • client_id: アプリのID。
  • redirect_uri: この引数は必須で、OAuthログインプロセスを開始した際に使用した、元のrequest_uriと同じでなければなりません。
  • client_secret: 固有のapp secretで、アプリダッシュボードに表示されます。このapp secretは、クライアント側のコードや逆コンパイルが可能なバイナリには含めないでください。app secretは、アプリと利用者のセキュリティの中核を成すものであるため、機密性を保つことが非常に重要です。
  • code。前述のログインダイアログリダイレクトから受け取ったパラメーター。

注: v2.3以降、このエンドポイントは固有のJSON応答を返すようになります。呼び出しでバージョンを指定しなかった場合は、デフォルトで、利用できる最も古いバージョンが設定されます。

応答

このエンドポイントから受け取る応答はJSON形式で返されます。成功すると、以下のようになります。

{
  "access_token": {access-token}, 
  "token_type": {type},
  "expires_in":  {seconds-til-expiration}
}

成功しなかった場合、エラーメッセージを受け取ります。

アクセストークンの検査

ログインダイアログから受け取るresponse_typeとして、codetokenのどちらを使用するかに関わりなく、アプリはアクセストークンを受け取ります。これらのトークンの検査をグラフAPIエンドポイントを使用して自動で行うことができます。

GET graph.facebook.com/debug_token?
     input_token={token-to-inspect}
     &access_token={app-token-or-admin-token}

このエンドポイントは次のパラメーターを受け取ります。

API呼び出しの応答は、検査対象のトークンに関するデータを含むJSON配列です。例:

{
    "data": {
        "app_id": 138483919580948, 
        "type": "USER",
        "application": "Social Cafe", 
        "expires_at": 1352419328, 
        "is_valid": true, 
        "issued_at": 1347235328, 
        "metadata": {
            "sso": "iphone-safari"
        }, 
        "scopes": [
            "email", 
            "publish_actions"
        ], 
        "user_id": "1207059"
    }
}

app_idフィールドとuser_idフィールドは、アクセストークンが利用者とアプリに対して有効かどうかをアプリが確認するのに役立ちます。その他のフィールドについて詳しくは、アクセストークンの情報の取得に関するガイドをご覧ください。

アクセス許可の確認

特定のユーザーによって付与または却下されたアクセス許可のリストを取得するため、/me/permissionsエッジを呼び出すことができます。アプリはこれを使って、リクエストされたアクセス許可のうち特定のユーザーに使用できないものを確認します。

却下されたアクセス許可の再リクエスト

Facebookログインでは、利用者は特定のアクセス許可をアプリと共有することを拒否できます。ログインダイアログには、次のような画面が表示されます。

public_profileアクセス許可は常に必須であり、無効にはできないためグレーアウトされています。

ただし、利用者がこの例のuser_likes (いいね!)にチェックをしない場合、付与されたアクセス許可を/me/permissionsで確認すると、次のような結果になります。

{
  "data":
    [
      {
        "permission":"public_profile",
        "status":"granted"
      },
      {
        "permission":"user_likes",
        "status":"declined"
      }
    ]
}

user_likesが付与されず、却下されたことがわかります。

利用者がアプリに対して却下したアクセス許可の付与をもう一度リクエストすることはできます。その場合は、アクセス許可の付与が必要な理由を説明する画面を表示して、再リクエストします。ただし、前回と同じ方法でログインダイアログを呼び出しでも、そのアクセス許可のリクエストはされません。

これは、利用者がアクセス許可を一度却下すると、却下されたアクセス許可の再リクエストを明示的にダイアログに指示しない限り、ログインダイアログで同じアクセス許可を再度リクエストすることはないためです。

再リクエストするには、次のようにauth_type=rerequestパラメーターをログインダイアログURLに追加します。

https://www.facebook.com/v21.0/dialog/oauth?
    client_id={app-id}
    &redirect_uri={redirect-uri}
    &auth_type=rerequest
    scope=email
   

これにより、却下されたアクセス許可がログインダイアログで再度リクエストされます。

アクセストークンとログインステータスの保存

フローのこの時点で、利用者は認証とログインを完了しています。アプリ側では、利用者に代わってAPI呼び出しを行う準備が整っています。呼び出しを行う前に、アクセストークンとアプリ利用者のログインステータスを保存してください。

アクセストークンの保存

前のステップでアプリがアクセストークンを受け取った後、アプリのあらゆる部分のAPI呼び出し時に使用できるように、アクセストークンを保存する必要があります。このステップには特定のプロセスはありませんが、一般にウェブアプリを構築している場合は、特定のユーザーのブラウザーセッションを識別するために、トークンをセッション変数として追加するとよいでしょう。ネイティブのデスクトップアプリやモバイルアプリを構築している場合は、アプリで利用可能なデータストアを使用してください。さらにアプリは、ユーザーを識別するuser_idと一緒に、トークンをデータベースに保存する必要もあります。

アクセストークンのドキュメントに記載されたアクセストークンのサイズに関する注記をご覧ください。

ログインステータスのトラッキング

前述のように、アプリは利用者のログインステータスを保存する必要があります。これにより、ログインダイアログの呼び出しを繰り返す必要がなくなります。どの手順を使うとしても、ログインステータスを確認できるように調整してください。

利用者のログアウト

追加したログインステータスのインジケーターの設定を解除すると、利用者をアプリからログアウトさせることができます(ログインしていることを示すセッションを削除するなど)。保存されているアクセストークンを削除する必要もあります。

利用者をログアウトさせることは、ログイン許可の取り消し(以前に付与した認証を削除すること)とは異なり、個別に行うことができます。そのため、ログアウトした利用者を強制的にログインダイアログに戻す自動処理を行わないようにアプリを構築してください。

アプリのアンインストールの検出

ユーザーはアプリ自体で操作することなく、Facebook.comからアプリをアンインストールできます。この操作が実行されたときにそれをアプリ側で検出できるようにするため、アプリでコールバックURLの許可取り消しを実行することが可能です。

Appダッシュボードでコールバックの許可取り消しを有効にすることができます。

ユーザーデータの削除リクエストへの対応

利用者はアプリに対し、Facebookから受け取った利用者に関する情報すべてを削除するようリクエストできます。このようなリクエストの対応については、データ削除リクエストのコールバックをご覧ください。