How do I use remembered devices in my Amazon Cognito user pool?

Last updated: 2020-01-08

I want to track devices that users in my Amazon Cognito user pool have used to sign in to my app. How do I do that?

Short Description

Amazon Cognito can track and remember devices that users in a user pool use for sign-in. By enabling device remembering, you can set sign-in restrictions (for example, to limit sign-in from a single device). Or, you can let users skip repeated sign-in on the same device. For more information, see Specifying User Pool Device Tracking Settings.

Note: The remembered devices functionality works only with the USER_SRP_AUTH authentication flow. Also, this functionality requires multi-factor authentication (MFA) to be enabled for the user pool.

Remembering devices is a two-part process:

  • Confirming a new device. Initiate authentication from the device, and then confirm it with Amazon Cognito to get unique device identifiers.
  • Verifying a confirmed device. Initiate authentication from a confirmed device to skip the MFA step on subsequent sign-in attempts.

Resolution

Note: The following instructions generally describe the Amazon Cognito API calls to make in your app client's code. If you're using a client-side SDK, such as the AWS Mobile SDKs for Android or iOS, much of the implementation is handled by the SDK.

Set up remembered devices

  1. In the Amazon Cognito console, choose Manage user pools, and then choose your user pool.
  2. In the left navigation pane, under General settings, choose Devices.
  3. For Do you want to remember your user's devices, choose Always or User Opt In. For more information, see Tracking and Remembering Devices Using Amazon Cognito Your User Pools.
  4. For Do you want to use a remembered device to suppress the second factor during multi-factor authentication (MFA), choose Yes or No. For more information, see Using Remembered Devices to Suppress Multi Factor Authentication (MFA).
    Note: If these options don't appear, MFA isn't enabled. To set up MFA, in the left navigation pane, choose MFA and verifications.
  5. Choose Save changes.

For more information, see Specifying User Pool Device Tracking Settings.

Call SetUserMFAPreference

In your app client's code, call the SetUserMFAPreference API to set the MFA preference to true for the MFA methods that you're using.

Call InitiateAuth

In your app client's code, call the InitiateAuth API to get the device keys. In this API request, be sure to include the following request parameters:

  • AuthFlow. Use USER_SRP_AUTH.
  • AuthParameters. Include the authentication parameters USERNAME, SRP_A, and SECRET_HASH.
    Note: SECRET_HASH is required only if your app client is configured with a client secret.

Calculate SRP_A using this formula:

SRP_A = ga (mod N)

  • Use g as defined in AuthenticationHelper.js on the AWS Amplify (JavaScript) GitHub repository.
  • Let a = 128 random bytes

For more information, see Request Syntax and the API reference for your chosen AWS SDK.

Call RespondToAuthChallenge for MFA challenges

After your app client makes the InitiateAuth API call, your Amazon Cognito user pool returns a set of MFA challenges based on the MFA methods that you enabled.

Your app must answer these challenges using the RespondToAuthChallenge API. For example, if you enabled SMS text message MFA in your user pool, include the parameter ChallengeName with the value SMS_MFA. For more information, see Request Syntax and the API reference for your chosen AWS SDK.

Store the device keys

When all MFA challenges are answered, Amazon Cognito responds with a DeviceGroupKey and a unique DeviceKey in the NewDeviceMetadataType field.

If you're using the AWS Mobile SDK for Android, iOS, or JavaScript in the Browser, these keys are automatically moved to the device's local storage by the application. If you're using another AWS SDK, be sure to design a similar key storage solution for your app.

Call ConfirmDevice

With the DeviceGroupKey and DeviceKey, create a secret using the Secure Remote Password (SRP) protocol, which generates a salt and a password verifier. Pass these to Amazon Cognito in a ConfirmDevice API call that includes the following request parameters:

  • AccessToken. Use a valid access token for the user.
  • DeviceKey. Use the unique key for the device, returned from Amazon Cognito.
  • DeviceName. Use a name that you give to the device. (The AWS Mobile SDKs use User Agent.)
  • DeviceSecretVerifierConfig. Include Salt (16 random bytes, base64-encoded) and PasswordVerifier.

For PasswordVerifier, use this formula:

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

  • Use g as defined in AuthenticationHelper.js on the AWS Amplify (JavaScript) GitHub repository.
  • Let FULL_PASSWORD = SHA256_HASH(DeviceGroupKey + username + ":" + RANDOM_PASSWORD)
  • Let RANDOM_PASSWORD = 40 random bytes, base64-encoded
  • Use N as defined in AuthenticationHelper.js on the AWS Amplify (JavaScript) GitHub repository.

For more information, see Request Syntax and the API reference for your chosen AWS SDK.

(Optional) Call UpdateDeviceStatus

When setting up remembered devices in your user pool, if you chose Always, you can skip this step. If you chose User Opt In, you must include an UpdateDeviceStatus API call.

Note: If you're using the Amazon Cognito Identity SDK for JavaScript, you must instead call setDeviceStatusRemembered or setDeviceStatusNotRemembered. For more information, see Usage in the SDK's README file on GitHub.

When you give your app's users an option to have their device remembered, confirming the device tracks it in your user pool as 'non-remembered.' You must ask the user whether they want to have it remembered, and then send their input using the UpdateDeviceStatus API.

Note: When opt-in is required, the user must opt-in before the device can be remembered and the MFA challenge can be suppressed.

Call InitiateAuth with the device key

In your app client's code, call the InitiateAuth API to verify a remembered device. In this call, include the device key in the request parameters as follows:

  • AuthFlow. Use USER_SRP_AUTH.
  • AuthParameters. Include the authentication parameters USERNAME, SRP_A, and DEVICE_KEY.

For more information, see Request Syntax and the API reference for your chosen AWS SDK.

Call RespondToAuthChallenge for DEVICE_SRP_AUTH

After your app client makes the InitiateAuth API call with a valid device key, your Amazon Cognito user pool returns the DEVICE_SRP_AUTH challenge. To respond, call the RespondToAuthChallenge API and include the following request parameters:

  • ChallengeName. Use DEVICE_SRP_AUTH.
  • ClientId. Use a valid app client ID.
  • ChallengeResponses. Include USERNAME, DEVICE_KEY, and SRP_A in these responses.
    Note: For SRP_A, use the formula mentioned earlier in these instructions.

After this API call, Amazon Cognito responds with one more challenge: DEVICE_PASSWORD_VERIFIER. In the response, you also get the values for the ChallengeParameters SECRET_BLOCK and SRP_B, which you need for responding to the challenge.

For more information, see Request Syntax and the API reference for your chosen AWS SDK.

Call RespondToAuthChallenge for DEVICE_PASSWORD_VERIFIER

To respond to the DEVICE_PASSWORD_VERIFIER challenge, call the RespondToAuthChallenge API and include the following request parameters:

  • ChallengeName. Use DEVICE_PASSWORD_VERIFIER.
  • ClientId. Use a valid app client ID.
  • ChallengeResponses. Include USERNAME, PASSWORD_CLAIM_SECRET_BLOCK, TIMESTAMP, PASSWORD_CLAIM_SIGNATURE, and DEVICE_KEY.

Define the challenge responses as follows:

  • For PASSWORD_CLAIM_SECRET_BLOCK, use the value of SECRET_BLOCK.
  • For TIMESTAMP, include the current time. (For example, Tue Sep 25 00:09:40 UTC 2018.)
  • Let PASSWORD_CLAIM_SIGNATURE = SHA256_HMAC(K_USER, DeviceGroupKey + DeviceKey + PASSWORD_CLAIM_SECRET_BLOCK + TIMESTAMP), base64-encoded
  • Let K_USER = SHA256_HASH(S_USER)
  • Let S_USER = (SRP_B - k * gx)(a + ux)
  • Let x = SHA256_HASH(salt + FULL_PASSWORD)
  • Let u = SHA256_HASH(SRP_A + SRP_B)
  • Let k = SHA256_HASH(N + g)

Get JSON web tokens from your user pool

After successfully responding to the last challenge, your Amazon Cognito user pool returns JSON web tokens in the AuthenticationResult:

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

Did this article help you?

Anything we could improve?


Need more help?