APIとSPAの構成(SPA + API)

このセクションでは、当社シナリオでAPIを実装する方法を説明します。

APIエンドポイントの定義

まず、APIのエンドポイントを定義する必要があります。

APIエンドポイントとは

APIエンドポイントは

たとえば、レストランAPIには/orders/customersなどのエンドポイントがあるかもしれません。このAPIに接続するアプリケーションは、関連するHTTPメソッド(POSTGETPUTPATCHDELETE)を使ってAPIエンドポイントを呼び出すことにより、CRUD操作(作成、読み取り、更新、削除)を実行することができます。

この実装では、2つのエンドポイントのみ定義します。1つは従業員の全タイムシートのリストを取得するため、もう1つは従業員がタイムシートエントリーを新規作成できるようにするためのものです。

/timesheetsエンドポイントへのHTTP GET要求は、ユーザーがタイムシートを取得できるようにし、/timesheetsへのHTTP POST要求は、ユーザーが新たなタイムシートを追加できるようにします。

Node.jsでの実装を参照してください

エンドポイントのセキュリティ確保

APIがヘッダーの一部にBearerアクセストークンのある要求を受け取った場合、最初にすべきことはトークンの検証です。これは複数の手順で構成され、そのうち1つでも失敗した場合、要求は、Missing or invalid tokenという呼び出し元アプリへのエラーメッセージとともに拒否されなければなりません。

APIは以下の検証を実行すべきです。

  • JWTが整形式であることを確認する

  • 署名を確認する

  • 標準クレームを検証する

検証プロセスにはアプリケーション権限(スコープ)の確認も含まれますが、これに関しては次の段落で別に説明します。

アクセストークン検証の詳細については、「アクセストークンを検証する」を参照してください。

Node.jsでの実装を参照してください

アプリケーション権限の確認

この段階ではJWTの有効性が検証されています。最後の手順は、アプリケーションが保護されたリソースにアクセスするために必要な権限を持っているかどうかを検証することです。

そのためには、APIがデコードされたJWTのスコープを確認する必要があります。このクレームはペイロードの一部で、スペースで区切られた文字列のリストです。

Node.jsでの実装を参照してください

ユーザーIDの判断

どちらのエンドポイント(タイムシートのリスト取得用と新規タイムシート追加用)でも、ユーザーのIDを判断する必要があります。

これは、タイムシートのリスト取得に関しては、要求元のユーザーのタイムシートのみを返すようにするためです。一方の新規タイムシートの追加に関しては、タイムシートがその要求元のユーザーと関連付けられていることを確認するためです。

標準JWTクレームの1つは、クレームの対象である本人を識別するsubクレームです。暗黙的付与フローの場合、このクレームにはAuth0ユーザーの一意の識別子であるIDが含まれます。これを使って、外部システムのいかなる情報でも、特定ユーザーに関連付けることができます。

また、カスタムクレームを使って、メールアドレスなど別のユーザー属性をアクセストークンに追加し、ユーザーを一意に識別することもできます。

Node.jsでの実装を参照してください

SPAの実装

このセクションでは、当社シナリオでSPAを実装する方法を説明します。

ユーザーの認証

ユーザーの認証にはauth0.jsライブラリが使われます。Auth0アプリケーションの新しいインスタンスを次のように初期化できます。

var auth0 = new auth0.WebAuth({
  clientID: '{yourClientId}',
  domain: '{yourDomain}',
  responseType: 'token id_token',
  audience: 'YOUR_API_IDENTIFIER',
  redirectUri: '{https://yourApp/callback}',
  scope: 'openid profile read:timesheets create:timesheets'
});

Was this helpful?

/

以下の構成値を渡す必要があります。

  • clientID:Auth0のクライアントIdの値。これはDashboardにある[Application(アプリケーション)]の[Settings(設定)]で取得できます。

  • domain:Auth0ドメインの値。これはDashboardにある[Application(アプリケーション)]の[Settings(設定)]で取得できます。

  • responseType:使用する認証フローです。暗黙フローを使うSPAの場合は、token id_tokenに設定します。tokenの部分はURLフラグメントでアクセストークンを返すフローをトリガーし、id_tokenの部分はIDトークンも返すフローをトリガーします。

  • audience:API識別子の値。これはDashboardにある[Settings of your API(APIの設定)]で取得できます。

  • redirectUri:ユーザー認証後のAuth0のリダイレクト先URL。

  • scope:IDトークンとアクセストークンで返される情報を決定するスコープopenid profileのスコープは、IDトークン中のユーザープロファイル情報をすべて返します。APIを呼び出すために必要なスコープも要求する必要があります。この場合は、read:timesheets create:timesheetsスコープです。そうすることで、アクセストークンにこれらのスコープがあるようにします。

認証フローを開始するには、authorize()メソッドを呼び出すことができます。

auth0.authorize();

Was this helpful?

/

Auth0は認証後、Auth0アプリケーションの新たなインスタンス構成時に指定したredirectUriに再びリダイレクトして戻ります。この時点で、URLハッシュフラグメントを解析するparseHash()メソッドを呼び出してAuth0認証応答の結果を抽出する必要があります。

parseHashが返すauthResultオブジェクトの内容は、どの認証パラメーターが使われたかによって異なります。以下を含む可能性があります。

  • idToken:ユーザープロファイル情報が入ったIDトークンJWT

  • accessTokenaudienceで指定されたAPIのアクセストークン

  • expiresIn:アクセストークンの有効期限(秒数)を含む文字列

トークンを保管するための最適な場所を決定します。シングルページアプリ(SPA)に1つでもバックエンドサーバーがあれば、トークンは認可コードフローまたはProof Key for Code Exchange(PKCE)を使った認可コードフローを使ってサーバー側で処理します。

対応するバックエンドサーバーがないSPAの場合、ログイン時に新しいトークンを要求し、それらをメモリ内に保存しますが、永続的に保存しないようにします。APIの呼び出しをするには、SPAがトークンのインメモリコピーを使用します。

SPAにおけるセッションの処理方法については、「JavaScriptシングルページアプリのQuickstart」で、「認可トークンの処理」セクションに記載されている例を参照してください。

Angular 2での実装を参照してください

ユーザープロファイルの取得

トークンから情報を抽出する

このセクションでは、アクセストークンと/userinfoエンドポイントを使って、ユーザー情報を取得する方法について説明します。APIの呼び出しを避けたい場合には、ライブラリーを使って、単にIDトークンをデコードすることもできます(必ず先に検証をしてください)。他のユーザー情報が追加で必要な場合は、バックエンドからのManagement APIの使用を検討してください。

ユーザーのプロファイル情報を取得するために、返されたauthResult.accessTokenを渡してclient.userInfoメソッドを呼び出すことができます。その場合、/userinfoエンドポイントに要求が送られ、以下の例によく似た、ユーザー情報が入ったuserオブジェクトが返されます。

{
    "email_verified": "false",
    "email": "test@example.com",
    "clientID": "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH",
    "updated_at": "2017-02-07T20:50:33.563Z",
    "name": "tester9@example.com",
    "picture": "https://gravatar.com/avatar/example.png",
    "user_id": "auth0|123456789012345678901234",
    "nickname": "tester9",
    "created_at": "2017-01-20T20:06:05.008Z",
    "sub": "auth0|123456789012345678901234"
}

Was this helpful?

/

これらのプロパティにはuserInfo関数を呼び出す際に渡されたコールバック関数でアクセスできます。

const accessToken = authResult.accessToken;

auth0.client.userInfo(accessToken, (err, profile) => {
  if (profile) {
    // Get the user’s nickname and profile image
    var nickname = profile.nickname;
    var picture = profile.picture;
  }
});

Was this helpful?

/

Angular 2での実装を参照してください

スコープに基づいた条件付きUI要素の表示

ユーザーのscopeに基づいて、特定のUI要素を表示または非表示にしたい場合があります。ユーザーに発行されたスコープを決めるには、最初に認可プロセスで要求されたスコープを保存する必要があります。ユーザーが認可されると、authResultscopeも返されます。

authResultscopeが空だと、要求したすべてのスコープが認められたことになります。authResultscopeが空でない場合は、異なる一連のスコープが認められ、authResult.scopeにあるスコープを使用すべきであることを意味します。

Angular 2での実装を参照してください

APIの呼び出し

APIから安全なリソースにアクセスするには、認証されたユーザーのアクセストークンを、送信される要求に入れる必要があります。これには、Bearerスキームを使用して、Authorizationヘッダー内でアクセストークンを送る必要があります。

Angular 2での実装を参照してください

アクセストークンの更新

安全のため、ユーザーアクセストークンのライフタイムは短くすることが推奨されます。Auth0 DashboardでAPIを作成する場合、デフォルトのライフタイムは7200秒(2時間)ですが、APIごとに制御できます。

いったん期限が切れたアクセストークンは、APIのアクセスに利用できなくなります。再びアクセスを得るには、新たなアクセストークンを得る必要があります。

最初のアクセストークンを取得する際に使った認証フローを繰り返すことで、新しいアクセストークンを取得できます。しかしこれは、SPAでは最適な方法とはいえません。ユーザーを現在のタスクからリダイレクトして再び認証フローを完了させるような手間をかけさせたくない場合があるからです。

そのような場合は、サイレント認証を使うとよいでしょう。サイレント認証で使われる認証フローでは、Auth0はリダイレクトでのみ返答して、ログインページで返答することはありません。しかし、このためにはユーザーはすでにシングルサインオン経由でログインしている必要があります。

Angular 2での実装を参照してください