使ってみよう! Windows Live SDK/API

第45回OAuth 2.0でLiveへコネクト!

はじめに

今回もLive ConnectによるWindows Liveサービスと統合したアプリ開発を紹介します。これまでJavaScript APIを利用してWebブラウザー上で動作するアプリ開発について紹介してきましたが、今回はWebサーバー上で動作するWebアプリからLive Connectを使ってみましょう。

Live Connectは、Windows Liveサービス上のユーザーデータにアプリからアクセスする仕組みとして、標準的なプロトコルOAuth 2.0(以下、OAuth)を用いています。JavaScript APIを利用しないということは、OAuthで定義されている手順を実装すればよいということです。今回の内容はLive Connectの利用を前提としていますが、OAuthを実装したサービスであれば、ほかのサービスも同様の手順で利用できます。

OAuth 2.0

OAuthは、Windows LiveなどのWebサービスに、サードパーティ製のアプリから、ユーザーに代わってアクセスが制限されたデータの参照などの操作を可能にします。Live Connectの場合、Live Messenger、Hotmail、SkyDriveといったWindows Liveサービスのユーザーデータにアクセスするアプリが作れます。

通常、ユーザーがアプリに対して許可を与えることで、アプリからのアクセスを可能にします。この許可の承諾は、前回までの内容でも登場していました。JavaScript APIを利用すると、その後の処理はOAuthのプロトコルをあまり意識せずユーザーデータにアクセスができていましたが、WebアプリではOAuthの手順を知る必要があります。

アプリがユーザーデータにアクセスするためには、Access Tokenアクセストークンと呼ばれる許可内容や有効期限を示した文字列を、認証・認可を行うサーバーから受け取る必要があります。

アクセストークンの有効期限は短いため、Refresh Tokenリフレッシュトークンと呼ばれる新しいアクセストークンを取得するための文字列も利用できます。Live Connectの場合、wl.offline_accessというScopeスコープを要求します。スコープは許可を示す値で、これまでにも登場しています。

続いて、アクセストークンを得るまでのフローをみてみましょう。

認可フロー

Live Connectでは、アクセストークンを得る2種類の方法をサポートしています。

Authorization Code Grant Flow

ひとつめは、Authorization Code認可コードを使用する方法です。認可コードは、アクセストークンやリフレッシュトークンを得るために一時的に使用します。この方法は、Webサーバー上で動作するアプリの使用が想定されています。

フローは、図1のようになります。

図1 Authorization Code Grant Flow
図1 Authorization Code Grant Flow

OAuthでは、4種類のRole(ロール)が登場します。リソースオーナーは、アプリへアクセス許可を与える存在です。通常はアプリの利用者です。クライアントは、アプリを表します。認可サーバーは、認証・認可処理、認可コードやアクセストークン、リフレッシュトークンを発行します。リソースサーバーは、ユーザーデータ(リソース)を持っているサーバーです。

また、もうひとつ重要なのが、ユーザーエージェントです。通常、ユーザーエージェントはWebブラウザーのことです。リソースオーナーは、ユーザーエージェントを通してクライアントやサーバーとやりとりします。

フローの手順は次の通りです。アプリ利用者がWebサイトにアクセスした後から始まります。

  • ①認証・認可画面(Webページ)へ移動します。通常、Webページにサインイン ボタンなどを表示し、アプリ利用者のクリックで移動します。移動先のLive Connect認可サーバーのエンドポイントは、以下のURLです。

    • https://oauth.live.com/authorize?client_id=CLIENT_ID&scope=SCOPES&response_type=code&redirect_uri=REDIRECT_URL

    URLのクエリーには、Client ID(クライアントID⁠⁠、スコープ、リダイレクト先のURLなどを指定します。

  • ②リソースオーナーは、Windows Liveサービスへのサインインと、アプリが要求する内容を許可します。

  • ③①で指定したリダイレクト先へ移動します。このとき、認可サーバーは、URLのクエリーに認可コードを付けてリダイレクトします。

    • http://example.jp/callback.php?code=[AuthorizationCode]

    Webアプリは、ユーザーエージェントを介して認可コードを受け取ります。

  • ④クライアントは、認可サーバーにアクセストークンを要求します。次のURLにアクセスします。

    • https://oauth.live.com/token?client_id=CLIENT_ID&redirect_uri=REDIRECT_URL&client_secret=CLIENT_SECRET&code=AUTHORIZATION_CODE&grant_type=authorization_code

    URLのクエリーには、クライアントID、リダイレクトURL、Client Secret(クライアントシークレット⁠⁠、認可コードなどを指定します。

  • ⑤認可サーバーは、アクセストークンを発行します。

以上が、認可のフローです。リフレッシュトークンは、リソースオーナーに認可された場合、アクセストークンと一緒に発行され、クライアントが受け取ります。

  • ⑥クライアントは、リソースサーバーにリソースのアクセスを要求します。Live Connectでは、REST APIを利用します。

Implicit Grant Flow

もうひとつのアクセストークンを取得する方法は、Webブラウザー上で動くアプリ向けの方法です。JavaScript APIはこの方法を使っています。デスクトップアプリでも使えます。

フローは、図2の通りです。

図2 Implicit Grant Flow
図2 Implicit Grant Flow

この場合のクライアントは、JavaScriptなどで実装されたWebブラウザー上で動作するアプリです。Webサーバーには、クライアントのリソース(HTML文書やスクリプト)があります。

フローの手順は次の通りです。

  • ①認証・認可画面(Webページ)へ移動します。

    • https://oauth.live.com/authorize?client_id=CLIENT_ID&scope=SCOPES&response_type=token&redirect_uri=REDIRECT_URL
  • ②リソースオーナーは、Windows Liveサービスへのサインインと、アプリが要求する内容を許可します。

  • ③①で指定したURLへリダイレクトします。このとき、認可サーバーは、URLのフラグメントにアクセストークンを付けてリダイレクトします。

    • http://example.jp/callback.html#access_token=[AccessToken]
  • ④ユーザーエージェントは、Webサーバー上のクライアントリソースのURLへリダイレクトします。このとき、URLの#以降のフラグメント部分にあるアクセストークンは、Webサーバーには送信されません。

  • ⑤クライアントリソースは、JavaScriptなどのスクリプトを含むHTML文書を返します。

  • ⑥ユーザーエージェントは、スクリプトを実行し、URLのフラグメントからアクセストークンを抽出します。

以上が、認可フローです。リソースへのアクセスは図では省略しています。リソースのアクセスは、ユーザーエージェントがアクセストークンを使ってリソースサーバーへ要求します。

ひとつめの認可コードを使う場合と比べると、アクセストークンをユーザーエージェントが持っている点が大きく異なります。また、この方法の場合、認可サーバーはリフレッシュトークンを発行しません。

以上が、OAuthで定義されている4種類のフローのうちの2種類でした。Live Connectでは、これ以外にJavaScript APIとサインインコントロールを使用したフローを用意しています。

サーバーサイドの処理

それでは、実際にWebサーバー上で動作するアプリのコードを書いてみましょう。認可コードによる方法を用います。今回は言語にPHPを使います。

前提条件として、アプリケーション設定サイトでアプリの登録を済ませている必要があります。アプリの登録は、第42回で説明しています。

認可コードの取得

認可コードを得るため、次のエンドポイントへアプリ利用者を誘導します。

  • https://oauth.live.com/authorize?client_id=CLIENT_ID&scope=SCOPES&response_type=code&redirect_uri=REDIRECT_URL

パラメーターは次の通りです。

名前説明
client_idクライアントID
scopeスコープ
複数の場合はスペース(URLエンコード「%20⁠⁠)でつなげます。
例: wl.signin%20wl.basic
response_typeレスポンスの種類
認可コードの場合 code
redirect_uriリダイレクトURL
ドメインは登録情報と一致している必要があります。

さらに次のパラメーターもオプションで指定できます。

名前説明
display認可画面の表示形式
popup, touch
locale認可画面の国・地域情報
例: ja
stateアプリで使用する任意の値
指定した場合、認可サーバーからのリダイレクトURLに同値が含まれます。

display=touchを指定すると、モバイル端末向けのデザインになります。

図3 モバイル端末向けの表示
図3 モバイル端末向けの表示

認可サーバーがリダイレクトしたとき、codeパラメーターに認可コードが含まれています。

  • http://example.jp/callback.php?code=[AuthorizationCode]

認可コードを取得するまでのPHPコードは、次のようにしました。認可画面へのリンクをコードで生成しています。

<?php
    define('CLIENT_ID',     'xxxxx');
    define('CLIENT_SECRET', 'xxxxx');
    define('REDIRECT_URI',  'http%3A%2F%2Fexample.jp%2F');

    if (isset($_GET['code'])) {
        // (認可コードからアクセストークン取得 処理を記述)
    }

    if (!$msg) {
        $signInUri = 'https://oauth.live.com/authorize' .
            '?client_id=' . CLIENT_ID .
            '&scope=wl.signin&20wl.offline_access' .
            '&response_type=code' .
            '&display=popup' .
            '&locale=ja' .
            '&redirect_uri=' . REDIRECT_URI;
    }
?>
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8" />
        <title>Server-Side Sample</title>
    </head>
    <body>
        <?php
        if ($signInUri) {
        ?>
        <div><a href="<?php echo $signInUri; ?>">サインイン</a></div>
        <?php
        } else {
            echo $msg;
        }
        ?>
    </body>
</html>

define部分はアプリにあわせて変更してください。上記のコードは、リダイレクト先を同じページとして処理を記述しています。

アクセストークンの取得

次は、アクセストークンを取得します。次のURLへHTTP POSTメソッドでアクセスします。

  • https://oauth.live.com/token?client_id=CLIENT_ID&redirect_uri=REDIRECT_URL&client_secret=CLIENT_SECRET&code=AUTHORIZATION_CODE&grant_type=authorization_code

パラメーターは次の通りです。

名前説明
client_idクライアントID
redirect_uriリダイレクトURL
ドメインは登録情報と一致している必要があります。
client_secretクライアントシークレット
code認可コード
grant_type認可コードを使用する場合
authorization_code

レスポンスは、JSON形式で次のような内容になります。

{
    "access_token": "xxxxx",
    "refresh_token": "xxxxx",
    "expires_in": 3600,
    "scope": "wl.signin wl.offline_access",
    "token_type": "bearer"
}

アクセストークン(access_token)のほかに、有効期限(expires_in)の秒数なども含まれています。リフレッシュトークン(refresh_token)は、スコープにwl.offline_accessを指定した場合に含まれています。

リソースのアクセス

続いて、リソースのアクセスです。リソースのアクセスはREST APIを利用します。次のURLへアクセスします。

  • https://apis.live.net/v5.0/REST_PATH?access_token=ACCESS_TOKEN

REST_PATHは、アクセスするリソースのパスを指定します。前回までに紹介した内容では、meやme/albumsなどのパスです。ACCESS_TOKENにはアクセストークンを指定します。HTTPのGETやPOSTメソッドのどれを使うかは、リソースの操作内容によって異なります。

ここまでの内容をコードで書いてみましょう。認可コードを受け取った場合、リクエストトークンの取得、REST APIの呼び出しまでまとめて行っています。

<?php
    define('CLIENT_ID',     'xxxxx');
    define('CLIENT_SECRET', 'xxxxx');
    define('REDIRECT_URI',  'http%3A%2F%2Fexample.jp%2F');

    if (isset($_GET['code'])) {
        $msg = createMessage($_GET['code']);
    }

    if (!$msg) {
        $signInUri = 'https://oauth.live.com/authorize' .
            '?client_id=' . CLIENT_ID .
            '&scope=wl.signin&20wl.offline_access' .
            '&response_type=code' .
            '&display=popup' .
            '&locale=ja' .
            '&redirect_uri=' . REDIRECT_URI;
    }

    function createMessage($code) {
        $tokens = getTokens($code);
        if (!$tokens) {
            return "Error";
        } else if (array_key_exists('error', $tokens)) {
            return $tokens['error']['error_description'];
        }

        $res = callRestApi($tokens['access_token']);
        if ($res === false) {
            return "Error";
        } else if (array_key_exists('error', $res)) {
            return $res['error']['message'];
        } else {
            return 'こんにちは ' . $res['name'] . ' さん';
        }
    }

    // 認可コードからアクセストークン取得
    function getTokens($code) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, 
            'https://oauth.live.com/token' .
            '?client_id=' . CLIENT_ID . 
            '&redirect_uri=' . REDIRECT_URI .
            '&client_secret=' . CLIENT_SECRET .
            '&code=' . $code .
            '&grant_type=authorization_code');
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        // (サーバー証明書を検証しない)
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);

        // エラーの場合 false を返す
        $res = curl_exec($ch);
        if ($no = curl_errno($ch)) {
            return false;
        }
        curl_close($ch);
        return json_decode($res, true);
    }

    // REST API の呼び出し (path が me 固定、GET メソッドのみ 対応)
    function callRestApi($token, $path) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, 
            'https://apis.live.net/v5.0/' .
            'me' . // path
            '?access_token=' . $token);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPGET, true);

        // (サーバー証明書を検証しない)
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);

        // エラーの場合 false を返す
        $res = curl_exec($ch);
        if ($no = curl_errno($ch)) {
            return false;
        }
        curl_close($ch);
        return json_decode($res, true);
    }
?>

上記コードは、REST APIを呼出し、サインインしているユーザーの名前を表示する単純な内容です。エラー処理はHTTP通信エラーの場合は省略、認可サーバーとREST APIのアクセスでエラーが発生したときはメッセージを表示する簡易的な記述しかしてありません。また、URLのクエリーのチェックは省略していますので注意してください。

リフレッシュトークンによる更新

リフレッシュトークンを使ったアクセストークンの更新方法についてもふれておきます。アクセストークンを更新するには次のURLにアクセスします。

  • https://oauth.live.com/token?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&client_secret=CLIENT_SECRET&refresh_token=REFRESH_TOKEN&grant_type=refresh_token

認可コードからアクセストークンを取得するときと比べ、codeパラメーターの代わりにrefrsh_tokenパラメーターを使用して、リフレッシュトークンを指定します。そして、grant_typeパラメーターにはrefresh_tokenを指定します。レスポンスは同様にJSON形式で得ます。

リフレッシュトークンを使用してアクセストークンを得るアプリの場合、データベースなどにリフレッシュトークンを保存し、ユーザー管理を行う必要があります。

おわりに

今回はここまでです。いかがでしたでしょうか。PHPを使った簡単なWebサーバー上で動作するアプリを紹介しました。サーバー側で処理すると、ユーザーがサインインしていないときにも(許可されていれば)ユーザーデータにアクセスでき、SNSサービスなどのアプリも作成可能です。次回は、まだ紹介できていないWindows Liveサービスのユーザーデータ(リソース)について紹介する予定です。

おすすめ記事

記事・ニュース一覧