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. With this feature, you can verify that your users own the email address 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

reCAPTCHA Enterprise's MFA works on top of the regular reCAPTCHA Enterprise workflow. At a high level, the MFA workflow is as follows:

  1. Instrument the critical workflow on the client.
  2. Create an assessment by using the token that is returned by the execute() call from the client. When creating the assessment, include the MFA parameters to obtain an MFA requestToken.
  3. Trigger an MFA challenge with the requestToken according to the channel that you want to use (only email supported).
  4. Verify the PIN entered by the end user in your web or mobile app.
  5. Request a new assessment by using the token that is returned in the verify request.

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 (email messages per second)
    • Peak QPS (email messages per second)
    • For email MFA, the sender address, and email addresses or domains you need during testing
  3. If you want to enable the email verification feature of MFA, do the following:

    1. In the Google Cloud console, go to the reCAPTCHA Enterprise page.

      Go to reCAPTCHA Enterprise

    2. Verify that the name of your project appears in the resource selector.

      If you don't see the name of your project, click the resource selector, then select your project.

    3. Click Settings.

    4. In the Multi Factor Authentication pane, click Configure.

    5. In the Configure MFA dialog, do the following:

      1. To enable email verification, click the Enable email toggle.
      2. In the Sender name box, enter your name.
      3. In the Sender email box, enter your email address.

    6. Click Save.

  4. Integrate reCAPTCHA Enterprise on the platforms for which you want to enable MFA by following the platform-specific instructions:

Instrument 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.

Request 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 Google Cloud CLI for authentication from your backend. To learn how to request an assessment, see Create an assessment.

Provide a hashed account identifier and one or more endpoints, such as an email address 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",
    }]
  }
}

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": "",
    }],
    "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.

In addition to the information related to MFA, the assessment response contains information related to account defender. The recommended_action field shows the possible action you can take before triggering the MFA challenge.

The following example shows a sample assessment that shows skip MFA as the recommended action:

{
  [...],
  "accountDefenderAssessment": {
    labels: ["PROFILE_MATCH"],
    "recommended_action": "SKIP_2FA"
  }
}

The recommended actions field can have any of the following values:

Value Description
RECOMMENDED_ACTION_UNSPECIFIED Indicates that account defender was not able to make a judgment for this request.
SKIP_2FA Indicates that account defender considers it is safe to skip MFA for this assessment. This usually means that the user has been verified recently for your site on this device.
REQUEST_2FA Indicates that you trigger an MFA challenge for the user. For more information, see account defender assessment response.

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 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.

Testing the MFA integration

For quickly testing the MFA integration, you can trigger the MFA challenge with a call to the challengeAccount() by providing 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.

The following example shows how to trigger the MFA challenge with a call to `challengeAccount():

grecaptcha.enterprise.challengeAccount(SITE_KEY, {
  'account-token': REQUEST_TOKEN_FROM_ASSESSMENT,
  'container': CONTAINER_HTML_COMPONENT_ID
}).then(newToken => {
  // Handle the new token.
});

If the challengeAccount() request is successful, an HTML component is displayed to enter the pin received. After the correct pin is entered, the newToken variable is passed to the chained function containing the verdict token to be verified through an assessment that is created in the backend.

On Websites

Create a verification handle and initiate a challenge with the following parameters:

// Initialize verification handle.
const verificationHandle = grecaptcha.enterprise.eap.initTwoFactorVerificationHandle(
  SITE_KEY,
  REQUEST_TOKEN_FROM_ASSESSMENT
);

// Call the challenge API.
verificationHandle.challengeAccount().then(
  (challengeResponse) => {
    if (challengeResponse.isSuccess()) {
      // Handle success: Usually this means displaying an input for the user to
      // enter the pin that they received and then call the `verifyAccount(pin)`
      // method described below.
    } else {
      // Handle API failure
    }
  });

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 ...
           }

         }
       });

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.
}

Verify an MFA code from the client

After you get the PIN from the end user, you must validate whether the pin is correct or not:

On Websites

Call verificationHandle.verifyAccount() with the PIN entered by the end user to verify that it was correct.

verificationHandle.verifyAccount(pin).then(
  (verifyResponse) => {
    if (verifyResponse.isSuccess()) {
      // Handle success: Send the result of `verifyResponse.getVerdictToken()`
      // to the backend in order to determine if the code was valid.
    } else {
      // Handle API failure
    }
  },
  (error) => {
    // Handle other errors
  }
);

On Android

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

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 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).