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:
- Instrument the critical workflow on the client.
- 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 MFArequestToken
. - Trigger an MFA challenge with the
requestToken
according to the channel that you want to use (only email supported). - Verify the PIN entered by the end user in your web or mobile app.
- Request a new assessment by using the token that is returned in the verify request.
Before you begin
Choose the best method for setting up reCAPTCHA Enterprise in your environment and complete the setup.
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
If you want to enable the email verification feature of MFA, do the following:
In the Google Cloud console, go to the reCAPTCHA Enterprise page.
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.
Click
Settings.In the Multi Factor Authentication pane, click Configure.
In the Configure MFA dialog, do the following:
- To enable email verification, click the Enable email toggle.
- In the Sender name box, enter your name.
In the Sender email box, enter your email address.
Click Save.
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.
Recommended actions
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). |