REST を使った認証

Epic Games の認証プロセスの概要

Epic Games のサービスは、認証と承認に OAuth 2.0 プロトコルを使用し、Web サーバーとクライアントサイド アプリケーションの一般的なユースケースをサポートします。Epic は、特定のユースケース向けにカスタムのグラント種別も導入しました。

始める前に、Epic から OAuth 2.0 クライアント資格情報を取得する必要があります。これらはクライアント ID とクライアント シークレットの形式で提供され、Epic 承認サーバーからアクセス トークンをリクエストする際に使用されます。詳細については「Epic アカウント サービス入門」を参照してください。

シナリオ

Epic Games ストアのゲーム クライアント

Epic Games ストアから起動したゲーム クライアントは、1 回限りの交換コードを使用して Epic の承認サーバーで認証されます。この交換コードは Epic Launcher によって生成され、コマンドライン引数としてその ゲーム クライアント に渡されます。

ゲーム クライアントが起動すると、クライアント資格情報と交換コードを含めた Epic トークン エンドポイントへのリクエストを送信します。応答には、アクセス トークンと、認証されたクライアントとアカウントに関する情報が含まれます。

ゲーム クライアントは、Epic サービスへのリクエストに毎回アクセストークンを添付します。アクセス トークンは、信頼されたゲーム サーバーに渡して検証したり、サービス間のリクエストで使用することもできます。

含めるべき更新トークンがある場合は、それも併せてトークンの応答に添付されます。ゲーム クライアントは、アクセス トークンの有効期限 (通常 2 時間) が切れたら更新トークンを使用する必要があります。これは通常、アクセス トークンが発行されてから 2 時間以内に発生します。

Epic Games Launcher の認証フローについての説明図。画像を拡大するにはクリックします。クリックして拡大表示。

Web サーバー アプリケーション

サーバーサイド アプリケーションの場合、まずユーザーは 承認コード を取得するために Web ブラウザーの Epic 承認フローに誘導されます。ユーザーは、Epic Games アカウントを使用してログインするよう求められます。さらに、アプリケーションの承認を求められる場合があります。承認されると、ユーザー エージェントはクエリ パラメータとして添付した承認コードとともに Web アプリケーションにリダイレクトします。

リダイレクト後、Web サーバーは、クライアント資格情報と承認コードを含めた Epic トークン エンドポイントへのリクエストを送信します。応答には、アクセス トークンと、認証されたクライアントとアカウントに関する情報が含まれます。

Web サーバーは、Epic サービスへのリクエストに毎回アクセストークンを添付します。

認証

認証フローの最初のステップとして、ユーザーは Epic アカウント サービスを使って認証手続きをしなければなりません。OAuth 2.0 による認証と、追加のカスタムグラント種別のみをサポートします。

クライアントが、トークンをリクエストするために必要な情報 (交換コード、承認コード、ユーザー資格情報など) を取得すると、アクセス トークンのリクエストを開始します。

アクセス トークンのリクエスト

アクセス トークンをリクエストするには、クライアントはクライアント資格情報 (クライアント ID とクライアント シークレット) とユーザー資格情報を渡して Epic トークン エンドポイントに HTTP リクエストを発行します。

Epic トークン エンドポイントは https://api.epicgames.dev/epic/oauth/v1/token です。

クライアント資格情報は Basic 承認を使用して Authorization ヘッダに渡されます。このエンドポイントは以下の POST パラメータをサポートします。

パラメータ名

説明

grant_type

使用されているグラント種別。exchange_codepassword または refresh_token

deployment_id

クライアントが認証を試みているデプロイメント ID。この ID は、デプロイを必要とする他のサービスとのやり取りに影響します。デプロイが公開されていない場合、資格の与えられたユーザーのみがログインできます。

scope

ユーザーが要求するスコープ (アクセス許可) のスペース区切りのリスト。例:basic profile friends_list presence

password グラント種別向け

username

password グラント種別でのみ使用される、アカウントのユーザー名 (メールアドレス)。

password

password グラント種別でのみ使用される、アカウントのパスワード。

exchange_code グラント種別向け

exchange_code

ランチャーがゲーム クライアントに渡す交換コード。 exchange_code グラント種別でのみ使用されます。

authorization_code グラント種別向け

code

承認サーバーから受信した承認コード。

client_credentials グラント種別向け (Web 認証 を参照)

client_id

アプリケーションの OAuth クライアント ID。

client_secret

アプリケーションの OAuth クライアント シークレット。

なお、これらのパラメータはリクエスト ボディに含める必要があります。クエリ パラメータは無視されます。

以下のスニペットはリクエストの例です ( password グラント種別を使用)

POST /epic/oauth/v1/token HTTP/1.1
Host: api.epicgames.dev
Content-Type: application/x-www-form-urlencoded
Authorization:Basic Zm9vOmJhcg==

grant_type=password&
deployment_id=foo&
scope=basic_profile friends_list presence&
username=user@example.com&
password=s3cr3t

応答には以下のフィールドが含まれます。

応答

説明

access_token

アクセス トークン。プレフィックスを含む場合があります (例:eg1~[token]) 。Epic サービスに対するすべてのリクエストで、この値は Bearer タイプを使用して、そのままの形で Authorization ヘッダに渡される必要があります。

expires_in

トークンの有効期限切れまでの秒数。

expires_at

ISO 8601 形式での有効期限日付。

account_id

トークンが発行されるユーザーの Epic アカウント ID。

client_id

このトークンを発行するために使用されるクライアント ID。

application_id

クライアントが関連付けられるアプリケーション ID。

token_id

発行されるトークンのタイプ。値は常に bearer です。

refresh_token

クライアントの設定に応じ、オプションでリフレッシュ トークンが返されます。このリフレッシュ トークンを使用して、有効期限の前または後でセッションを延長することができます。

refresh_expires

リフレッシュ トークンが有効期限になるまでの秒数。

refresh_expires_at

リフレッシュ トークン の ISO 8601 形式での有効期限日付。

以下のスニペットはリクエストの例です。

{
  "scope": "basic_profile friends_list presence",
  "token_type": "bearer",
  "access_token": "eyJ0IjoiZXBpY19pZCIsImFsZyI6IlJTMjU2Iiwia2lkIjoibldVQzlxSFVldWRHcnBXb3FvVXVHZkFIYmVWM2NsRnlsdFRYMzhFbXJKSSJ9.eyJhdWQiOiJ4eXphNzg5MWxoeE1WWUdDT043TGduS1paOEhRR0Q1SCIsInN1YiI6Ijk2MjZmNDQxMDU1MzQ5Y2U4Y2I3ZDdkNWE0ODNlYWEyIiwidCI6ImVwaWNfaWQiLCJzY29wZSI6ImJhc2ljX3Byb2ZpbGUgZnJpZW5kc19saXN0IHByZXNlbmNlIiwiYXBwaWQiOiJmZ2hpNDU2N08wM0hST3hFandibjdrZ1hwQmhuaFd3diIsImlzcyI6Imh0dHBzOlwvXC9hcGkuZXBpY2dhbWVzLmRldlwvZXBpY1wvb2F1dGhcL3YxIiwiZG4iOiJLcm5icnkiLCJleHAiOjE1ODgyODYwODMsImlhdCI6MTU4ODI3ODg4Mywibm9uY2UiOiJuLUI1cGNsSXZaSkJaQU1KTDVsNkdvUnJDTzNiRT0iLCJqdGkiOiI2NGMzMGQwMjk4YTM0MzdjOGE3NGU1OTAxYzM0ODZiNSJ9.MZRoCRpjIb--dD7hxoo2GvjSPhUSNpOq1FhtShTBmzMJ1qlHFPzNaUiAEETAc3mabGPKyOxUP6Q1FBadr_P_UtbtB7kf34hN2VTv5czW6WOx1HdpjwUQZuxFyDc_aix7FCS0Egu4rZlC65b-B0FUVlial_s_FrH8ou5L_d-4I0KVpIwtv-b_M6EQ9jtLdQRfMaP6aV0rIerrbqFZ617Pe7XT4IO9jZFwM8F5aDTeDHkkOO41wyVibrm38799lP4B65RIv9CwbAL-TVmV1L5gFYITaZhi5ShfZzTvxAk-3Dxwp8c5JvcO68zpbya5gFSAfhsd7vt9YLU0gQR2uXq3Vw",
  "refresh_token": "eyJ0IjoiZXBpY19pZCIsImFsZyI6IlJTMjU2Iiwia2lkIjoibldVQzlxSFVldWRHcnBXb3FvVXVHZkFIYmVWM2NsRnlsdFRYMzhFbXJKSSJ9.eyJhdWQiOiJ4eXphNzg5MWxoeE1WWUdDT043TGduS1paOEhRR0Q1SCIsInN1YiI6Ijk2MjZmNDQxMDU1MzQ5Y2U4Y2I3ZDdkNWE0ODNlYWEyIiwidCI6ImVwaWNfaWQiLCJhcHBpZCI6ImZnaGk0NTY3TzAzSFJPeEVqd2JuN2tnWHBCaG5oV3d2Iiwic2NvcGUiOiJiYXNpY19wcm9maWxlIGZyaWVuZHNfbGlzdCBwcmVzZW5jZSIsImlzcyI6Imh0dHBzOlwvXC9hcGkuZXBpY2dhbWVzLmRldlwvZXBpY1wvb2F1dGhcL3YxIiwiZG4iOiJLcm5icnkiLCJleHAiOjE1ODgzMDc2ODMsImlhdCI6MTU4ODI3ODg4MywianRpIjoiYzczYjA2NmUyZDU4NGVkNTk0NjZiOThiNzI3NzJiMjAifQ.O-eVa46NimubKwxe9SwlHxciivu0XWe1-DSL74mMiA_PpPoW0yKL9DfmsLxiPCwsRB5_hQTc6_FM7G1FyfKtX_VVAp90MZPkhCbAbfKmTpQVcL0Ya6kve4KMG8KxeLVfLLhubCbJTYlnDNVHobbpvpQtHd8Ys321ZNDJj05l_tnZzdgus-xmCO6orX4UP4wDd1jAOXXeqRT47OXuLCgSE0q6Osfh-ENPwh6ph1i7ld759xPV0oNcQb8XiPxnT6_FUmFugzG1YS1z9bTnVWmbP2RmYluue5VQm5EKGJZ91Alve8s2eNEtDfUqaBLZ45pqGkc1KjbYTtP0a_1ue2BpkQ",
  "expires_in":7200,
  "expires_at":"2020-04-30T22:34:43.549Z",
  "refresh_expires_in":28800,
  "refresh_expires_at":"2020-05-01T04:34:43.549Z",
  "account_id":"9626f441055349ce8cb7d7d5a483eaa2",
  "client_id": "xyza7891lhxMVYGCON7LgnKZZ8HQGD5H",
  "application_id": "fghi4567O03HROxEjwbn7kgXpBhnhWwv"
}

このアクセス トークンは、Epic サービスへの Authorization ヘッダに常にそのままの形で渡される必要があります。以下はその例です。Bearer eyJraWQiOiJ0RkM...`

Web アプリケーション

Web アプリケーションおよびサーバーサイド アプリケーションの場合は、アクセス トークンを要求する前に承認コードを取得する必要があります。Web 承認を使用する前に、Epic OAuth クライアントをリダイレクト URL を使用して構成する必要があります。

フローを開始するには、アプリケーションがユーザーを承認ページにリダイレクトする必要があり、ユーザーはそこで Epic Games アカウントへのログインを要求されます。承認 URL は以下のとおりです。

https://www.epicgames.com/id/authorize?client_id={client_id}&response_type=code&scope=basic_profile

追加パラメータ redirect_uri={redirect_uri} を使って複数のリダイレクト URL を定義することができます。2 つ以上のリダイレクトに対する認証 URL は以下になります。

https://www.epicgames.com/id/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&scope=basic_profile

ユーザーはログイン後、承認コードとともに設定したリダイレクト URL にリダイレクトされます。アプリケーションは「アクセス トークンのリクエスト」で解説したように、このコードを利用して authorization_code グラント種別が使用されるアクセス トークンを取得します。

また Epic では、リクエストとコールバック間の状態の維持を可能にしたり、 クロスサイト リクエスト フォージェリ攻撃 の防止に使用される、オプションの state パラメータをサポートしています。

以下はユーザーの認証後のリダイレクト先の例です。

https://www.example.com/?code=cfd1de1a8d224203b0445fe977838d81&state=rfGWJux2WL86Zxr6nKApCAnDo8KexEUE

アクセス トークンの検証

オフライン検証

アクセス トークンは、トークンの信頼性を検証するために使用されるヘッダーと署名を含む JWT (JSON Web トークン) です。

シグネチャを検証する前に、Epic のサービスから JSON Web キー (JWK) として公開された 公開鍵 を取得してください。Epic は現在のすべての公開鍵を格納する JWK セット 形式を使用した単一のエンドポイントを用意しています。キーは頻繁には変更されませんが、予告なくローテーションする可能性があります。

JWK のエンドポイントはこちらです。https://api.epicgames.dev/epic/oauth/v1/.well-known/jwks.json

公開鍵をフェッチするクライアントは、妥当な期間、それらをキャッシュしなければなりません。鍵がローテーションしても、与えられた鍵の ID のキーは変わりません。

以下のスニペットは公開鍵のエンドポイントからの応答例です。

{"keys":[{"kty":"RSA","e":"AQAB","kid":"WMS7EnkIGpcH9DGZsv2WcY9xsuFnZCtxZjj4Ahb-_8E","n":"l6XI48ujknQQlsJgpGXg4l2i_DuUxuG2GXTzkOG7UtX4MqkVBCfW1t1JIIc8q0kCInC2oBwhC599ZCmd-cOi0kS7Aquv68fjERIRK9oCUnF_lJg296jV8xcalFY0FOWX--qX3xGKL33VjJBMIrIu7ETjj06s-v4li22CnHmu2lDkrp_FPTVzFscn-XRIojqIFb7pKRFPt27m12FNE_Rd9bqlVCkvMNuE7VTpTOrSfKk5B01M5IuXKXk0pTAWnelqaD9bHjAExe2I_183lp_uFhNN4hLTjOojxl-dK8Jy2OCPEAsg5rs9Lwttp3zZ--y0sM7UttN2dE0w3F2f352MNQ"}]}

オンライン検証

オフライン検証が選択できない場合、有効なアクセス トークンを使用してトークン情報のエンドポイントを呼び出すこで、オンラインでの検証が実行可能です。このエンドポイントは、 トークン イントロスペクション の仕様を実装しています。

トークン情報エンドポイントはこちらです。https://api.epicgames.dev/epic/oauth/v1/tokenInfo

以下のスニペットはトークンを検証するリクエストの例です。

POST /epic/oauth/v1/tokenInfo HTTP/1.1
Host: api.epicgames.dev
Content-Type: application/x-www-form-urlencoded
token=eyJ0IjoiZXBpY19pZCIsImFsZyI6IlJTMjU2Iiwia2lkIjoibldVQzlxSFVldWRHcnBXb3FvVXVHZkFIYmVWM2NsRnlsdFRYMzhFbXJKSSJ9.eyJhdWQiOiJ4eXphNzg5MWxoeE1WWUdDT043TGduS1paOEhRR0Q1SCIsInN1YiI6Ijk2MjZmNDQxMDU1MzQ5Y2U4Y2I3ZDdkNWE0ODNlYWEyIiwidCI6ImVwaWNfaWQiLCJzY29wZSI6ImJhc2ljX3Byb2ZpbGUgZnJpZW5kc19saXN0IHByZXNlbmNlIiwiYXBwaWQiOiJmZ2hpNDU2N08wM0hST3hFandibjdrZ1hwQmhuaFd3diIsImlzcyI6Imh0dHBzOlwvXC9hcGkuZXBpY2dhbWVzLmRldlwvZXBpY1wvb2F1dGhcL3YxIiwiZG4iOiJLcm5icnkiLCJleHAiOjE1ODgyODYwODMsImlhdCI6MTU4ODI3ODg4Mywibm9uY2UiOiJuLUI1cGNsSXZaSkJaQU1KTDVsNkdvUnJDTzNiRT0iLCJqdGkiOiI2NGMzMGQwMjk4YTM0MzdjOGE3NGU1OTAxYzM0ODZiNSJ9.MZRoCRpjIb--dD7hxoo2GvjSPhUSNpOq1FhtShTBmzMJ1qlHFPzNaUiAEETAc3mabGPKyOxUP6Q1FBadr_P_UtbtB7kf34hN2VTv5czW6WOx1HdpjwUQZuxFyDc_aix7FCS0Egu4rZlC65b-B0FUVlial_s_FrH8ou5L_d-4I0KVpIwtv-b_M6EQ9jtLdQRfMaP6aV0rIerrbqFZ617Pe7XT4IO9jZFwM8F5aDTeDHkkOO41wyVibrm38799lP4B65RIv9CwbAL-TVmV1L5gFYITaZhi5ShfZzTvxAk-3Dxwp8c5JvcO68zpbya5gFSAfhsd7vt9YLU0gQR2uXq3Vw

以下のスニペットはトークン情報エンドポイントからの応答例です。

{
  "active": true,
  "scope": "basic_profile friends_list presence",
  "token_type": "bearer",
  "expires_in":6761,
  "expires_at":"2020-04-30T22:34:43.549Z",
  "account_id":"9626f441055349ce8cb7d7d5a483eaa2",
  "client_id": "xyza7891lhxMVYGCON7LgnKZZ8HQGD5H",
  "application_id": "fghi4567O03HROxEjwbn7kgXpBhnhWwv"
}

このエンドポイントを使用すれば、アクセス トークンと更新トークンの両方を検証できます。

Epic Games ストアのゲーム クライアント

Epic Games Store を介して接続されたゲーム クライアントを使用する場合、ゲーム クライアントは exchange_code グラント種別を使用して、クライアント資格情報と、ランチャーからゲームに渡されたコードを転送することで、アクセス トークンを取得します。

開発中は password グラント種別を使用することもできます。これにより、ランチャーと統合しなくても Epic Services はゲーム クライアントを認証することができるようになります。

ゲームが Epic Games Launcher によって開始されるとき、以下のコマンドライン パラメータで起動されます。

パラメータ

説明

AUTH_LOGIN

交換コードでは使用されません。

AUTH_PASSWORD

ゲーム クライアントで使用される資格情報。認証サーバーに渡される交換コードが含まれます。

epicapp

内部アプリケーション名。

epicenv

(常に Prod) で起動される環境。

epicusername

ランチャーで認証されるアカウントの表示名。

epicuserid

ランチャーで認証される Epic アカウント ID。

epiclocale

ユーザー設定に基づいた、または、システム言語に基づいた優先ロケール。

epicovt

所有権検証トークン情報が記述されたファイルへの完全パス。

以下は、ランチャーが渡すコマンド ライン パラメータの例です。

-AUTH_LOGIN=unused -AUTH_PASSWORD=ed642dfd4e6f47bf8354caf1bcab2fc2 -AUTH_TYPE=exchangecode -epicapp=[AppName] -epicenv=Prod -epicusername="DisplayName" -epicuserid=ab1f86d911d74f4aa8399849e9ca9aa5 -epiclocale=en-US
-epicovt="C:/AppName/.egstore/ab1f86d911d74f4aa8399849e9ca9aa5/File.ovt"

アカウント情報

アクセス トークンを取得すると、ユーザーを代理して Epic サービスにリクエストを送信することができます。例えば、この機能を使用して、ユーザーやフレンドの表示名が取得できます。

アクセス トークン経由

アクセス トークンから直接情報を取得することもできます。アクセス トークンは、JSON Web Token (JWT) としてエンコードされ、ヘッダーにはトークンと署名の種類、ユーザー、クライアント、セッションおよび署名などのペイロードについての情報を記述されます。ライブラリを使用して JWT をデコードすることを推奨しますが、できない場合は、仕様を参照してください。

ペイロードには以下のアイテムが含まれます。

クレーム

説明

iss

文字列

トークンを発行した Epic Games 認証サーバーのベース URI。

sub

文字列

このクレームは、client_credentials グラント種別の使用時は存在しません。

aud

文字列

承認リクエストで指定されたクライアント ID。

iat

整数

トークンが発行された時刻を示す UNIX タイムスタンプ。

exp

整数

トークンの有効期限を示す UNIX タイムスタンプ。

jti

文字列

このトークン固有の ID。

t

文字列

トークンの種類。常に epic_id となります。これにより、EG1 トークンのバージョン プレフィックスが置き換えられます。

scope

文字列

ユーザーに承認されたスコープのスペース区切りのリスト。

dn

文字列

ユーザーの表示名。

appid

文字列

承認リクエストで指定されたアプリケーション ID。

pfpid

文字列

トークン リクエストで指定されたデプロイメント対象の製品 ID。

pfsid

文字列

トークン リクエストで指定されたデプロイ対象のサンドボックス ID。

pfdid

文字列

トークン リクエストで指定されたデプロイ ID。

前の例のトークンを使用して、ペイロードをデコードすると、以下の内容が確認できます。

{
  "aud": "xyza7891lhxMVYGCON7LgnKZZ8HQGD5H",
  "sub":"9626f441055349ce8cb7d7d5a483eaa2",
  "t": "epic_id",
  "scope": "basic_profile friends_list presence",
  "appid": "fghi4567O03HROxEjwbn7kgXpBhnhWwv",
  "iss": "https://api.epicgames.dev/epic/oauth/v1",
  "dn":"Krnbry",
  "exp":1588286083,
  "iat":1588278883,
  "nonce": "n-B5pclIvZJBZAMJL5l6GoRrCO3bE=",
  "jti":"64c30d0298a3437c8a74e5901c3486b5"
}

アカウントの取得

アクセス トークンの情報に加えて、ログインしたアカウント、またはアプリケーションとやり取りした他のアカウントについての同様の情報を要求することもできます。

プライバシーへの懸念から、こちら側からの事前申請に同意済みのユーザーに対してのみアカウント情報をリクエストできます。

アカウント情報エンドポイントは「https://api.epicgames.dev/epic/id/v1/accounts」です。このエンドポイントを呼び出す際は、解決したいアカウントに対して 1 つ以上の accountId クエリ パラメータを指定する必要があります。リクエスト 1 回 あたり 50 アカウントに制限されています。

以下のスニペットは複数アカウントを取得するリクエストの例です。

GET /epic/id/v1/accounts?accountId=foo531f86d911d74f4aa8399849e9ca9ba6&accountId=barcbab941052f540c69fbd92ddc3bf9027 HTTP/1.1
Host: api.epicgames.dev
Content-Type: application/x-www-form-urlencoded
Authorization:Bearer [token]eyJ0IjoiZXBpY19pZCIsImFsZyI6IlJTMjU2Iiwia2lkIjoibldVQzlxSFVldWRHcnBXb3FvVXVHZkFIYmVWM2NsRnlsdFRYMzhFbXJKSSJ9.eyJhdWQiOiJ4eXphNzg5MWxoeE1WWUdDT043TGduS1paOEhRR0Q1SCIsInN1YiI6Ijk2MjZmNDQxMDU1MzQ5Y2U4Y2I3ZDdkNWE0ODNlYWEyIiwidCI6ImVwaWNfaWQiLCJzY29wZSI6ImJhc2ljX3Byb2ZpbGUgZnJpZW5kc19saXN0IHByZXNlbmNlIiwiYXBwaWQiOiJmZ2hpNDU2N08wM0hST3hFandibjdrZ1hwQmhuaFd3diIsImlzcyI6Imh0dHBzOlwvXC9hcGkuZXBpY2dhbWVzLmRldlwvZXBpY1wvb2F1dGhcL3YxIiwiZG4iOiJLcm5icnkiLCJleHAiOjE1ODgyODYwODMsImlhdCI6MTU4ODI3ODg4Mywibm9uY2UiOiJuLUI1cGNsSXZaSkJaQU1KTDVsNkdvUnJDTzNiRT0iLCJqdGkiOiI2NGMzMGQwMjk4YTM0MzdjOGE3NGU1OTAxYzM0ODZiNSJ9.MZRoCRpjIb--dD7hxoo2GvjSPhUSNpOq1FhtShTBmzMJ1qlHFPzNaUiAEETAc3mabGPKyOxUP6Q1FBadr_P_UtbtB7kf34hN2VTv5czW6WOx1HdpjwUQZuxFyDc_aix7FCS0Egu4rZlC65b-B0FUVlial_s_FrH8ou5L_d-4I0KVpIwtv-b_M6EQ9jtLdQRfMaP6aV0rIerrbqFZ617Pe7XT4IO9jZFwM8F5aDTeDHkkOO41wyVibrm38799lP4B65RIv9CwbAL-TVmV1L5gFYITaZhi5ShfZzTvxAk-3Dxwp8c5JvcO68zpbya5gFSAfhsd7vt9YLU0gQR2uXq3Vw

次のスニペットは、このリクエストからの応答例です。

[
    {
        "accountId":"531f86d911d74f4aa8399849e9ca9ba6",
        "displayName": "eas_user",
        "preferredLanguage": "en",
        "linkedAccounts": [
            {
                "identityProviderId": "xbl",
                "displayName": "eas_user_xbl"
            }
        ]
    },
    {
        "accountId": "cbab941052f540c69fbd92ddc3bf9027",
        "displayName": "other_user",
        "preferredLanguage": "en"
    }
]