Integrating with the email verification feature

This page explains how to integrate with the email verification feature.

Email verification is a feature that allows you to verify that your users own the email address that is associated with their account. It can help protect your users against credential stuffing attacks. This feature allows you to send a verification code by email and provides an input screen to validate the user's response. You can retrieve the verification results on the risk assessment.

The integration of the email verification feature is done in a few steps:

  1. Instrument the critical flow (login, signup, etc.) on the client, before requesting the assessment.
  2. Request and interpret the email verification information in the assessment.
  3. Trigger an email verification challenge on the client.
  4. Request a new assessment to make sure that the user's email was successfully verified.

Before you begin

The email verification feature is whitelist-only for now. Please reach out to our sales team to onboard your site to this feature.

Make sure to complete the steps in the Quickstart to gain access to the API. Depending on the platforms for which you want to enable email verification, you will also need to follow the client-specific integration guides:

Instrumenting the critical flow on the client

This section explains how to pass the necessary information to reCAPTCHA Enterprise for use in the risk assessment.

On Android

Add the user's email address to the RecaptchaAction which will be used in execute calls. This can be done as follows:

Bundle bundle = new Bundle();
bundle.putString("username", "foo@bar.com");
RecaptchaAction action =
  new RecaptchaAction(
    new RecaptchaActionType(RecaptchaActionType.LOGIN), bundle));

On iOS

You will need to provide the username argument. For example:

recaptchaClient.execute(
   RecaptchaAction(
      action: .login,
      extraParameters: ["username": "foo@bar.com"])
).then { token in
   // Do something with the token
}.catch { error in
   // Act on the error.
}

On Web

You will need to append an additional username parameter to your execute call, for example:

grecaptcha.enterprise.execute({
  action: 'login',
  username: 'foo@bar.com
}).then(token => {
  /// Handle the generated token.
});

Note that execute returns a promise that is resolved upon token generation.

Requesting an assessment

Regardless of the platform that created the token, you can follow the instructions to create an assessment using that token.

If the integration with the feature is successful, the assessment should contain more information related to email verification specifically. For example:

{
  [...],
  "accountVerification": {
    "username": "foo@bar.com",
    "emailAccount": {
      "address": "foo@bar.com"
    },
    "requestToken": "tplIUFvvJUIpLaOH0hIVj2H71t5Z9mDK2RhB1SAGSIUOgOIsBv",
    "lastSuccessTime": "",
    "latestVerificationResult": "RESULT_UNSPECIFIED"
  }
}

The assessment will contain the date and time of the latest successful verification for the given email address on the device that issued the token, if any. It will also contain a requestToken field, which contains an opaque blob that you will need to send back to the client, if you decide to trigger an email verification challenge.

Triggering an email verification challenge on the client

If you have have decided to challenge the user based on the information contained in the assessment, then you must send the email verification request token from the assessment back to the client. This request token will be needed to trigger the email verification challenge.

On Android

The email challenge is sent with a call to challengeAccount from an Activity 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 ...
           }

         }
       });

Once you obtain the PIN from the user, you must 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

The challenge is triggered 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.
}

Then once you get the PIN from the user you can use the verifyPin of the verificationHandler to finish the verification.

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

On Web

The challenge is triggered with a single function call:

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

where containerHTMLComponentID is the ID of an HTML component in which the verification challenge should be rendered. If you do not specify this parameter, then the challenge will be rendered in an overlay on top of the page.

The challengeAccount function returns a promise that is resolved once the challenge is completed, or rejected in case of error or timeout. Upon completion, the resolver is given a new generated token that contains updated information to be retrieved by requesting a new assessment.

Requesting a new assessment

Once the flow has been completed on the client, you should have received a new token that you can use to get the verdict of the verification you triggered. The assessment should contain a very recent timestamp regarding the latest successful verification, along with a success result status:

{
  [...],
  "accountVerification": {
    "username": "foo@bar.com",
    "emailAccount": {
      "address": "foo@bar.com"
    },
    "requestToken": "kQTpUlCwbntaVvXXE9VHSP7T2wEHl6Ok7rTyd3KMzuhrGZGv6y",
    "lastSuccessTime": "2020-03-23 08:27:12 PST",
    "latestVerificationResult": "SUCCESS_USER_VERIFIED"
  }
}

The field latestVerificationResult can also show a different status, including:

  • ERROR_USER_NOT_VERIFIED if the user failed the verification challenge
  • ERROR_SITE_ONBOARDING_INCOMPLETE if your site is not properly onboarded to the feature
  • ERROR_CRITICAL_INTERNAL if the verification could not be completed due to an internal error in our systems.