Configuring Multi-factor authentication

This page describes how to configure Multi-factor authentication (MFA) that lets you verify your users' identity by sending a verification code by email or SMS. With this feature, you can verify that your users own the email address or phone number that is associated with their account. MFA can help protect your users against credential stuffing attacks and account takeovers (ATOs).

MFA is available for the score-based site keys and is not available for the checkbox site keys.

Understanding the configuration process of MFA

To configure MFA, follow these steps:

  1. Instrument the critical workflow (login, signup, etc.) on the client.
  2. Request and interpret the MFA information in the assessment.
  3. Trigger an MFA challenge on the client.
  4. Request a new assessment to make sure that the user's email address or phone number was successfully verified.

Before you begin

  1. Choose the best method for setting up reCAPTCHA Enterprise in your environment and complete the setup.

  2. MFA is accessible after a security review. Contact our sales team to onboard your site to this feature. Provide the following onboarding information to the sales team: :

    • Google Cloud project number
    • Site keys to onboard
    • Average QPS (emails/SMS per second)
    • Peak QPS (emails/SMS per second)
    • For email MFA, the sender address, and email addresses or domains you need during testing
    • For SMS MFA, the Peak and Average QPS per destination country (your user's country)
  3. Integrate reCAPTCHA Enterprise on the platforms for which you want to enable MFA by following the platform-specific instructions:

Instrumenting the critical workflow on the client

Pass the necessary information to reCAPTCHA Enterprise through the execute() function for the risk assessment. The execute() function returns a promise that is resolved upon token generation.

On Websites

Append an additional twofactor parameter to your execute() function as shown in the following sample code:

grecaptcha.enterprise.execute(SITE_KEY, {
  action: 'login',
  twofactor: true
}).then(token => {
  /// Handle the generated token.
});

On Android

Follow the instructions to generate token for your Android application. No additional parameter is required.

On iOS

Follow the instructions to generate token for your iOS application. No additional parameter is required.

Requesting an assessment

With the token that is generated by the execute() function, make an assessment request using either the reCAPTCHA Enterprise Client Libraries or the gcloud command-line tool for authentication.

Provide a hashed account identifier and one or more endpoints, such as an email address and a phone number to verify in the assessment. The hashed account identifier is an anonymous, persistent identifier for a user account that is unique to your website. Use a one-way hash of a stable account identifier. We recommend using sha256-hmac with a stable secret that you do not share with us.

{
  "event": {
    "token": "token",
    "siteKey": "key",
    "hashedAccountId": "BP3ptt00D9W7UMzFmsPdEjNH3Chpi8bo40R6YW2b"
  },
  "accountVerification": {
    "endpoints": [{
      "emailAddress": "foo@bar.com",
    },
    {
      "phoneNumber": "+11111111111",
    }]
  }
}

If the integration with the feature is successful, the assessment must contain more information related to MFA as shown in the following example:

{
  [...],
  "accountVerification": {
    "endpoints": [{
      "emailAddress": "foo@bar.com",
      "requestToken": "tplIUFvvJUIpLaOH0hIVj2H71t5Z9mDK2RhB1SAGSIUOgOIsBv",
      "lastVerificationTime": "",
    },
    {
      "phoneNumber": "+11111111111",
      "requestToken": "fwdgk0kcg1W0mbpetYlgTZKyrp4IHKzjgRkb6vLNZeBQhWdR3a",
      "lastVerificationTime": "",
    }],
    "latestVerificationResult": "RESULT_UNSPECIFIED"
  }
}

The assessment contains the date and time of the latest successful verification for the given endpoints on the device that issued the token, if any. It also contains one requestToken field per endpoint, which contains an encrypted string. If you decide to trigger an MFA challenge for that endpoint, you must send this encrypted string back to the client. The request tokens are valid for 15 minutes.

Triggering an MFA challenge on the client

If you have decided to challenge the user based on the information contained in the assessment, then send the MFA request token for the endpoint you want to verify from the assessment back to the client. This request token is required to trigger the MFA challenge.

Trigger the MFA challenge with a call to the challengeAccount(). The challengeAccount() function returns a promise that is resolved after the challenge is completed, or rejected if there was an error or timeout. Upon completion, a new token that contains updated information is generated, which is then sent for assessment.

On Websites

Trigger the MFA challenge with a call to the challengeAccount() function as shown in the following example.

Provide the following values:

  • REQUEST_TOKEN_FROM_ASSESSMENT: Value of the requestToken field from the assessment response.
  • CONTAINER_HTML_COMPONENT_ID: ID of an HTML component in which the verification challenge must be rendered. If you do not specify this parameter, then the challenge is rendered in an overlay on top of the page.
grecaptcha.enterprise.challengeAccount(SITE_KEY, {
  'account-token': REQUEST_TOKEN_FROM_ASSESSMENT,
  'container': CONTAINER_HTML_COMPONENT_ID
}).then(newToken => {
  // Handle the new token.
});

On Android

Trigger the MFA challenge with a call to challengeAccount() from a Context in your app.

Recaptcha.getClient(this)
   .challengeAccount(recaptchaHandle, requestToken)
   .addOnSuccessListener(
       this,
       new OnSuccessListener<VerificationHandle>() {
         @Override
         public void onSuccess(VerificationHandle handle) {
           VerificationHandle verificationHandle = handle;
           // Handle success ...
         }
       })
   .addOnFailureListener(
       this,
       new OnFailureListener() {
         @Override
         public void onFailure(@NonNull Exception e) {
           if (e instanceof ApiException) {
              ApiException apiException = (ApiException) e;
              Status apiErrorStatus = apiException.getStatusCode();
              // Handle API errors ...
           } else {
              // Handle other failures ...
           }

         }
       });

After you obtain the PIN from the user, call verifyAccount() from an Activity in your app to verify that the entered PIN was correct.

Recaptcha.getClient(this)
   .verifyAccount("userProvidedPIN", recaptchaHandle)
   .addOnSuccessListener(
       this,
       new OnSuccessListener<VerificationResult>() {
         @Override
         public void onSuccess(VerificationResult result) {
           if (result.getVerificationStatus().isSuccess()) {
             String recaptchaToken = result.recaptchaToken().orNull()
             // Handle success ...
           } else {
             VerificationHandle verificationHandle =
                              result.verificationHandle().orNull();
             Status errorStatus = result.getVerificationStatus();
             // Handle retries ...
           }
         }
       })
   .addOnFailureListener(
       this,
       new OnFailureListener() {
         @Override
         public void onFailure(@NonNull Exception e) {
           if (e instanceof ApiException) {
              ApiException apiException = (ApiException) e;
              Status apiErrorStatus = apiException.getStatusCode();
              // Handle API errors ...
           } else {
              // Handle other failures ...
           }
         }
       });

On iOS

Trigger the MFA challenge with a call to challengeAccount().

recaptchaClient.challengeAccount(withRequestToken: "Request Token").then { verificationHandler in
  // Show your UI and retrieve the pin from the user.
}.catch { error in
  // Handle error.
}

After you get the PIN from the user, call the verifyPin() method of the verificationHandler object to complete the verification.

handler.verifyPin("PIN") { recaptchaToken, recaptchaError in
  // Handle token/error.
}

Requesting a new assessment

Request a new assessment with the hashed account identifier and endpoints field.

After the workflow is completed on the client, you receive a new token that you can use to get the verdict of the verification you triggered. The assessment contains a recent timestamp regarding the latest successful verification, along with a success result status.

The following example shows a sample assessment that you receive upon requesting a new assessment using the new token obtained from the client.

{
  [...],
  "accountVerification": {
    "endpoints": [{
      "emailAddress": "foo@bar.com",
      "requestToken": "tplIUFvvJUIpLaOH0hIVj2H71t5Z9mDK2RhB1SAGSIUOgOIsBv",
      "lastVerificationTime": "2020-03-23 08:27:12 PST",
    }],
    "latestVerificationResult": "SUCCESS_USER_VERIFIED"
  }
}

The field latestVerificationResult can show a different status as listed in the following table:

Verification result status Description
SUCCESS_USER_VERIFIED The user was successfully verified.
ERROR_USER_NOT_VERIFIED The user failed the verification challenge.
ERROR_SITE_ONBOARDING_INCOMPLETE Your site is not properly onboarded to use the feature.
ERROR_RECIPIENT_NOT_ALLOWED This recipient is not approved for sending SMS or email to (during testing only).
ERROR_RECIPIENT_ABUSE_LIMIT_EXHAUSTED This recipient has already received too many verification codes in a short period.
ERROR_CUSTOMER_QUOTA_EXHAUSTED You have exceeded your available MFA quota.
ERROR_CRITICAL_INTERNAL The verification is not completed due to an internal error in our systems.
RESULT_UNSPECIFIED No information about the latest verification (never verified).