Amazon Cognito のユーザープールで記憶済みデバイスを使用するには、どうすれば良いですか?

最終更新日: 2020 年 1 月 8 日

Amazon Cognito のユーザープールのユーザーがアプリのサインインに使用したデバイスを追跡したいと考えています。どうすれば良いですか?

簡単な説明

Amazon Cognito は、ユーザープールのユーザーがサインインに使用するデバイスを追跡および記憶できます。デバイスの記憶を有効にすることで、サインインの制限を設定できます (たとえば、ある 1 つのデバイスからのサインインを制限する)。または、同じデバイスからのサインインの繰り返しをスキップできます。詳細については、「ユーザープールデバイス追跡設定の指定」を参照してください。

注意: 記憶済みデバイスの機能は、USER_SRP_AUTH 認証フローによってのみ機能します。この機能ではまた、ユーザープールの多要素認証 (MFA) を有効にする必要があります。

デバイスの記憶には 2 つのパートのプロセスがあります。

  • 新しいデバイスの確認。デバイスから認証を開始し、Amazon Cognito で確認して、一意のデバイス識別子を取得します。
  • 確認済みデバイスの検証。確認済みデバイスから認証を開始し、それ以降のサインイン試行では MFA ステップをスキップします。

解決方法

注意: 次の手順では、通常、アプリクライアントのコードで実行する Amazon Cognito API コールについて説明します。Android または iOS 向け AWS Mobile SDK などのクライアントサイド SDK を使用している場合は、実装の多くは SDK によって処理されます。

記憶済みデバイスのセットアップ

  1. Amazon Cognito コンソールで、[ユーザープールの管理] を選択し、次にユーザープールを選択します。
  2. 左のナビゲーションペインの [全般設定] で、[デバイス] を選択します。
  3. [ユーザーのデバイスを記憶しますか?] では、[常に] または [User Opt In] を選択します。詳細については、Tracking and Remembering Devices Using Amazon Cognito Your User Pools を参照してください。
  4. [記憶済みのデバイスを使用して、多要素認証 (MFA) 中に 2 つ目の要素を抑制しますか?] では、[Yes] または [No] を選択します。詳細については、「記憶済みデバイスを使用した Multi-Factor Authentication (MFA) の停止」を参照してください。
    注意: これらのオプションが表示されない場合は、MFA は有効になっていません。MFA をセットアップするには、左のナビゲーションペインで 、[MFA そして確認] を選択します。
  5. [変更の保存] を選択します。

詳細については、「ユーザープールデバイス追跡設定の指定」を参照してください。

SetUserMFAPreference の呼び出し

アプリクライアントのコードで、SetUserMFAPreference API を呼び出して、使用している MFA メソッドの MFA 設定を [true] に設定します。

InitiateAuth の呼び出し

アプリクライアントのコードで、InitiateAuth API を呼び出してデバイスキーを取得します。この API リクエストには、必ず次のリクエストパラメータを含めてください。

  • AuthFlowUSER_SRP_AUTH を使用します。
  • AuthParameters。認証パラメータには、USERNAMESRP_ASECRET_HASH を含めます。
    注意: SECRET_HASH は、アプリクライアントがクライアントシークレットを使用して設定されている場合のみ必要です。

次の式を使用して SRP_A を計算します。

SRP_A = ga (mod N)

  • AWS Amplify (JavaScript) GitHub リポジトリの AuthenticationHelper.js で定義されているとおりに g を使用します。
  • a = 128 ランダムバイトとします。

詳細については、Request Syntax および選択した AWS SDK の API リファレンスを参照してください。

MFA チャレンジに対する RespondToAuthChallenge の呼び出し

アプリクライアントが InitiateAuth API を呼び出すと、Amazon Cognito ユーザープールによって、有効な MFA メソッドに基づく MFA チャレンジのセットが返されます。

アプリは、RespondToAuthChallenge API を使用するこれらのチャレンジに応答する必要があります。たとえば、ユーザープールで SMS テキストメッセージの MFA を有効にした場合は、パラメータ ChallengeNameSMS_MFA の値を含めます。詳細については、Request Syntax および選択した AWS SDK の API リファレンスを参照してください。

デバイスキーの保存

すべての MFA チャレンジに応答すると、Amazon Cognito は NewDeviceMetadataType フィールドの DeviceGroupKey および一意の DeviceKey で応答します。

Android、iOS、JavaScript のいずれか向けの AWS Mobile SDK をブラウザで使用している場合は、これらのキーはアプリケーションによってデバイスのローカルストレージに自動的に移動されます。ほかの AWS SDK を使用している場合は、同様のキーストレージソリューションをアプリに設計するようにしてください。

ConfirmDevice の呼び出し

DeviceGroupKey および DeviceKey を使用して、Secure Remote Password (SRP) プロトコルでシークレットを作成します。SRP では、ソルトとパスワードの検証が生成されます。以下の リクエストパラメータを含む ConfirmDevice API 呼び出しで、これらを Amazon Cognito に渡します。

  • AccessToken。ユーザーの有効なアクセストークンを使用します。
  • DeviceKey。Amazon Cognito から返されたデバイスの一意のキーを使用します。
  • DeviceName。デバイスに付ける名前を使用します。(AWS Mobile SDK はユーザーエージェントを使用します。)
  • DeviceSecretVerifierConfigSalt (16 ランダムバイト、base64 エンコード) および PasswordVerifier を含めます。

PasswordVerifier には、次の式を使用します。

PasswordVerifier = g(salt + FULL_PASSWORD) (mod N)

  • AWS Amplify (JavaScript) GitHub リポジトリの AuthenticationHelper.js で定義されているとおりに g を使用します。
  • FULL_PASSWORD = SHA256_HASH(DeviceGroupKey + username + ":" + RANDOM_PASSWORD) とします。
  • RANDOM_PASSWORD = 40 random bytes, base64-encoded とします。
  • AWS Amplify (JavaScript) GitHub リポジトリの AuthenticationHelper.js で定義されているように N を使用します。

詳細については、Request Syntax および選択した AWS SDK の API リファレンスを参照してください。

(オプション) UpdateDeviceStatus の呼び出し

ユーザープールで記憶済みデバイスを設定するときに [常に] を選択した場合は、このステップをスキップできます。[User Opt In] を選択した場合は、UpdateDeviceStatus API コールを含める必要があります。

注意: Amazon Cognito Identity SDK for JavaScript を使用している場合は、代わりに setDeviceStatusRemembered または setDeviceStatusNotRememberedを呼び出す必要があります。詳細については、GitHub の SDK の README ファイルの Usage を参照してください。

アプリのユーザーにデバイスを記憶するオプションを付与する場合は、デバイスによってユーザープールで「記憶されていない」ものとして追跡されることを確認します。 記憶させるかをユーザーに確認し、次に UpdateDeviceStatus API を使用して入力を送信する必要があります。

注意: オプトインが必要な場合は、ユーザーはオプトインしてからデバイスを記憶し、MFA チャレンジを抑制する必要があります。

デバイスキーによる InitiateAuth の呼び出し

アプリクライアントのコードで、InitiateAuth API を呼び出して、記憶済みデバイスを検証します。この呼び出しでは、次のようにリクエストパラメータにデバイスキーを含めます。

  • AuthFlowUSER_SRP_AUTH を使用します。
  • AuthParameters。認証パラメータ USERNAMESRP_ADEVICE_KEY を含めます。

詳細については、Request Syntax および選択した AWS SDK の API リファレンスを参照してください。

DEVICE_SRP_AUTH に対する RespondToAuthChallenge の呼び出し

アプリクライアントが有効なデバイスキーを使用して InitiateAuth API を呼び出すと、Amazon Cognito のユーザープールは DEVICE_SRP_AUTH チャレンジを返します。応答するには、RespondToAuthChallenge API を呼び出し、次のリクエストパラメータを含めます。

  • ChallengeNameDEVICE_SRP_AUTH を使用します。
  • ClientId。有効なアプリクライアント ID を使用します。
  • ChallengeResponses。これらの応答には USERNAMEDEVICE_KEYSRP_A を含めます。
    注意: SRP_A の場合は、前述した式をこれらの手順で使用します。

この API を呼び出すと、Amazon Cognito はもう 1 つのチャレンジ DEVICE_PASSWORD_VERIFIER で応答します。この応答では、チャレンジへの応答に必要な ChallengeParametersSECRET_BLOCK および SRP_B の値も取得します。

詳細については、Request Syntax および選択した AWS SDK の API リファレンスを参照してください。

DEVICE_PASSWORD_VERIFIER に対する RespondToAuthChallenge の呼び出し

DEVICE_PASSWORD_VERIFIER チャレンジに応答するには、RespondToAuthChallenge API を呼び出し、次のリクエストパラメータを含めます。

  • ChallengeNameDEVICE_PASSWORD_VERIFIERを使用します。
  • ClientId。有効なアプリクライアント ID を使用します。
  • ChallengeResponsesUSERNAMEPASSWORD_CLAIM_SECRET_BLOCKTIMESTAMPPASSWORD_CLAIM_SIGNATUREDEVICE_KEY を含めます。

チャレンジへの応答を次のように定義します。

  • PASSWORD_CLAIM_SECRET_BLOCK では、SECRET_BLOCK の値を使用します。
  • TIMESTAMP には、現在の時刻を含めます。(例: Tue Sep 25 00:09:40 UTC 2018)
  • PASSWORD_CLAIM_SIGNATURE =SHA256_HMAC(K_USER, DeviceGroupKey+DeviceKey+PASSWORD_CLAIM_SECRET_BLOCK+TIMESTAMP), base64-encoded とします。
  • K_USER =SHA256_HASH(S_USER) とします。
  • S_USER = (SRP_B - k * gx)(a + ux) とします。
  • x =SHA256_HASH(salt+FULL_PASSWORD) とします。
  • u =SHA256_HASH(SRP_A+SRP_B) とします、
  • k =SHA256_HASH(N+g) とします。

ユーザープールから JSON ウェブトークンの取得

最後のチャレンジに正常に応答すると、Amazon Cognito ユーザープールにより AuthenticationResult で JSON ウェブトークンが返されます。

{ 
    "AuthenticationResult": { 
        "AccessToken": "...", 
        "ExpiresIn": 3600, 
        "IdToken": "...", 
        "RefreshToken": "...", 
        "TokenType": "Bearer" 
    }, 
    "ChallengeParameters": {} 
}

この記事はお役に立ちましたか?

改善できることはありますか?


さらにサポートが必要な場合