ユーザープロファイル情報を取得する


ユーザープロファイル情報を取得する

Amazonユーザープロファイルへのアクセスをユーザーがウェブサイトに許可すると、アクセストークンが返されます。サーバー側のスクリプトで認可コードグラントを使用してアクセストークンをリクエストしている場合、アクセストークンはアクセストークンレスポンスで返されます。

インプリシットグラントを使用している場合は、認可レスポンスでURIフラグメントとして返されます。許可されたユーザーデータにアクセスするには、HTTPSを使用して、受け取ったアクセストークンをLogin with Amazonに送信します。

そのレスポンスとして、Login with Amazonは該当するユーザープロファイルデータを返します。ここで返されるプロファイルデータは、アクセスをリクエストする際にscopeで指定したスコープによって決まります。アクセストークンに従って、そのスコープにアクセスできるようになります。

JavaScript用のLogin with Amazon SDKを使用する

JavaScript用のLogin with Amazon SDKでは、amazon.Login.retrieveProfileを使用してアクセストークンをプロファイルと交換します。次に例を示します。

<script type="text/javascript">
    document.getElementById('LoginWithAmazon').onclick = function() {
       setTimeout(window.doLogin, l);
       return false;
    };
    window.doLogin = function() {
      options = {};
      options.scope = 'profile';
      amazon.Login.authorize(options, function(response) {
         if ( response.error ) {
             alert('oauthエラー' + response.error);
         return;
         }
         amazon.Login.retrieveProfile(response.access_token, function(response) {
             alert('こんにちは。' + response.profile.Name);
             alert('あなたのEメールアドレス:' + response.profile.PrimaryEmail);
             alert('あなたの一意のID:' + response.profile.CustomerId);
             if ( window.console && window.console.log )
                window.console.log(response);
         });
     });
   };
 </script>

amazon.Login.retrieveProfile関数は、successerrorprofileの3つのパラメーターを返します。successは、呼び出しが成功したかどうかを表します。errorは、エラーが発生した場合にエラーメッセージを返します。エラーが発生しなければ、profileにユーザーのプロファイルが返されます。このメソッドとパラメーターの詳細については、JavaScript用のLogin with Amazon SDKリファレンスを参照してください。

サーバー側でprofileエンドポイントを呼び出す

profileエンドポイントを直接呼び出す場合、アクセストークンを指定する方法は、クエリパラメーターとして指定する、Bearerトークンとして指定する、HTTPヘッダーにx-amz-access-tokenを使用する、の3とおりあります。次に例を示します。

https://api.amazon.com/user/profile?access_token=AtzaIIQEBLjAsAhRmHjNgHpi0UDme37rR6CuUpSR...
GET /user/profile HTTP/1.1
Host: api.amazon.com
Date: Wed, 0l Jun 20ll l2:00:00 GMT
Authorization: Bearer Atza|IQEBLjAsAhRmHjNgHpi0U-Dme37rR6CuUpSR...
GET /user/profile HTTP/1.1
Host: api.amazon.com
Date: Wed, 0l Jun 20ll l2:00:00 GMT
x-amz-access-token: Atza|IQEBLjAsAhRmHjNgHpi0U-Dme37rR6CuUpSR...

Login with Amazonは、コンテンツタイプとしてapplication/jsonのみを、コンテンツ言語としてen-usのみをサポートします。明記されていない場合でも、Login with Amazonではこのコンテンツタイプと言語をデフォルトで使用します。

GET /user/profile HTTP/1.1
Host: api.amazon.com
Date: Wed, 0l Jun 20ll l2:00:00 GMT
x-amz-access-token: Atza|IQEBLjAsAhRmHjNgHpi0U-Dme37rR6CuUpSR...
Accept: application/json
Accept-Language: en-US

以下の各言語の詳細なコードサンプルは次のようになります。

PHPのサンプル

サーバー側のアプリで、/handle_login.phpに対するリクエストを処理し、アクセストークンとプロファイルREST APIを使用してプロファイル情報を取得します。次のコードサンプルを使用する場合は、YOUR-CLIENT-IDをアプリの登録時に取得したクライアントIDに置き換えます。

// アクセストークンがこちらに属していることを検証する
$c = curl_init('https://api.amazon.com/auth/o2/tokeninfo?access_token=' . urlencode($_REQUEST['access_token']));
curl_setopt($c, CURLOPT_RETURNTRANSFER, true);

$r = curl_exec($c);
curl_close($c);
$d = json_decode($r);

if ($d->aud != 'YOUR-CLIENT-ID') {
  // アクセストークンがこちらに属していない
  header('HTTP/1.1 404 Not Found');
  echo 'ページが見つかりません';
  exit;
}

// アクセストークンをユーザープロファイルと交換する
$c = curl_init('https://api.amazon.com/user/profile');
curl_setopt($c, CURLOPT_HTTPHEADER, array('Authorization: bearer ' . $_REQUEST['access_token']));
curl_setopt($c, CURLOPT_RETURNTRANSFER, true);

$r = curl_exec($c);
curl_close($c);
$d = json_decode($r);

echo sprintf('%s %s %s', $d->name, $d->email, $d->user_id);
Rubyのサンプル

サーバー側のアプリで、/handle_login.phpに対するリクエストを処理し、アクセストークンとプロファイルREST APIを使用してプロファイル情報を取得します。次のコードサンプルを使用する場合は、YOUR-CLIENT-IDをアプリの登録時に取得したクライアントIDに置き換えます。

require "rubygems"
require "net/https"
require "json"
require "uri"

...

# アクセストークンがこちらに属していることを検証する
uri = URI.parse("https://api.amazon.com/auth/o2/tokeninfo?access_token=" + URI.encode(access_token))
req = Net::HTTP::Get.new(uri.request_uri)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER

response = http.request(req)
decode = JSON.parse(response.body)

if decode['aud'] != 'YOUR-CLIENT-ID'
# アクセストークンがこちらに属していない
raise "無効なトークン"
end

# アクセストークンをユーザープロファイルと交換する
uri = URI.parse("https://api.amazon.com/user/profile")
req = Net::HTTP::Get.new(uri.request_uri)
req['Authorization'] = "bearer " + access_token
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER

response = http.request(req)
decode = JSON.parse(response.body)

puts sprintf "%s %s %s", decode['name'], decode['email'], decode['user_id']
Javaのサンプル

サーバー側のアプリで、/handle_login.phpに対するリクエストを処理し、アクセストークンとプロファイルREST APIを使用してプロファイル情報を取得します。次のコードサンプルを使用する場合は、YOUR-CLIENT-IDをアプリの登録時に取得したクライアントIDに置き換えます。

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.client.fluent.Content;
import org.apache.http.client.fluent.Request;
import java.net.URLEncoder;
import java.util.Map;

...

// アクセストークンがこちらに属していることを検証する
Content c = Request.Get("https://api.amazon.com/auth/o2/tokeninfo?access_token=" + URLEncoder.encode(access_token, "UTF-8"))
               .execute()
               .returnContent();

Map m = new ObjectMapper().readValue(c.toString(), new TypeReference>(){});

if (!"YOUR-CLIENT-ID".equals(m.get("aud"))) {
// アクセストークンがこちらに属していない
throw new RuntimeException("無効なトークン");
}

// アクセストークンをユーザープロファイルと交換する
c = Request.Get("https://api.amazon.com/user/profile")
       .addHeader("Authorization", "bearer " + access_token)
       .execute()
       .returnContent();

m = new ObjectMapper().readValue(c.toString(), new TypeReference>(){});

System.out.println(String.format("%s %s %s", m.get("name"), m.get("email"), m.get("user_id")));
Pythonのサンプル

サーバー側のアプリで、/handle_login.phpに対するリクエストを処理し、アクセストークンとプロファイルREST APIを使用してプロファイル情報を取得します。次のコードサンプルを使用する場合は、YOUR-CLIENT-IDをアプリの登録時に取得したクライアントIDに置き換えます。

import pycurl
import urllib
import json
import StringIO

...

b = StringIO.StringIO()

# アクセストークンがこちらに属していることを検証する
c = pycurl.Curl()
c.setopt(pycurl.URL, "https://api.amazon.com/auth/o2/tokeninfo?access_token=" + urllib.quote_plus(access_token))
c.setopt(pycurl.SSL_VERIFYPEER, 1)
c.setopt(pycurl.WRITEFUNCTION, b.write)

c.perform()
d = json.loads(b.getvalue())

if d['aud'] != 'YOUR-CLIENT-ID' :
# アクセストークンがこちらに属していない
raise BaseException("無効なトークン")

# アクセストークンをユーザープロファイルと交換する
b = StringIO.StringIO()

c = pycurl.Curl()
c.setopt(pycurl.URL, "https://api.amazon.com/user/profile")
c.setopt(pycurl.HTTPHEADER, ["Authorization: bearer " + access_token])
c.setopt(pycurl.SSL_VERIFYPEER, 1)
c.setopt(pycurl.WRITEFUNCTION, b.write)

c.perform()
d = json.loads(b.getvalue())

print "%s %s %s"%(d['name'], d['email'], d['user_id'])

ユーザープロファイルのレスポンス

アクセストークンが有効な場合、ユーザーのプロファイルデータはJSON形式のHTTPレスポンスとして返されます。次に例を示します。

HTTP/1.1 200 OK
 x-amzn-RequestId: 0f6bef6d-705c-lle2-aacb-93e6bf26930l
 Content-Type: application/json
 Content-Language: en-US
 Content-Length: 85
 {
    "user_id": "amznl.account.K2LI23KL2LK2",
    "email":"mhashimoto-04@plaxo.com",
    "name" :"Mork Hashimoto",
    "postal_code": "98052"
 }

Request-Idはログ用であり、無視して構いません。Login with Amazonチームと問題のトラブルシューティングを行う場合、Request-Idの提供をAmazonチームに求められることがあります。

プロファイルリクエストの処理中に問題が発生すると、HTTPエラーが返されます。アクセスリクエストのエラーコードには、次のものがあります。

ステータス エラーコード 説明
200 成功 リクエストに成功しました。
400 invalid_request リクエストに必須パラメーターが含まれていないか、形式に誤りがあります。
400 invalid_token 提供されたアクセストークンは、期限切れ、取り消し済み、形式の誤り、またはそのほかの理由により無効です。
401 insufficient_scope 提供されたアクセストークンでは、必要なスコープにアクセスできません。
500 ServerError サーバーでランタイムエラーが発生しました。

エラーコードに加えて、詳しい情報を含むJSONペイロードが返されることもあります。次に例を示します。

HTTP/1.1 400 Bad Request
Content-Type: application/json;charset=UTF-8
Content-Length: 74
{
"error": "機械可読なエラーコード",
"error_description": "人が読み取れる形式のエラーコード",
"request_id": "bef0c2f8-e292-4l96-8c95-8833fbd559df"
}

サーバーにユーザー情報を取り込む

Amazonから取得したユーザープロファイル情報をバックエンドサーバーに取り込むことで、サインインしたユーザーを特定したり、ユーザーのアカウントをさらにカスタマイズしたりできます。これを安全に行うため、HTTPSを使用してクライアントからサーバーにアクセストークンを送信します。次にサーバー側からそのアクセストークンを使用して、profileエンドポイントを呼び出します。詳細と各種言語のコードサンプルについては、サーバー側でprofileエンドポイントを呼び出すを参照してください。Login with Amazonからは、user_idemailnamepostal_codeなどの値を含んだユーザープロファイルレスポンスが返されるので、それをサーバーに保存できます。

この手順を踏むことで、サーバーに保存したプロファイルデータを、クライアントにサインインしているユーザーに確実に対応付けることができます。バックエンドにおけるユーザーアカウントの結合と管理の詳細については、既存のアカウントシステムと統合するを参照してください。