Sitecore - Google ReCaptcha V3
Tags: sitecore
Published: 2021-02-11 04:54:20

Google developed reCaptcha V3 to improve the accuracy of bot detection and for better user experience. Unlike V2, V3 is transparent as a hidden element and continuously monitors the visitor’s behavior to determine whether it’s a human or a bot.
![alt text](https://dev-to-uploads.s3.amazonaws.com/i/ab1lh5tm4ehb29vzqvbq.png)

Below you can find step by step process to create Google reCaptcha V3 field in Sitecore Forms.

* Create a new model class - GoogleRecaptchaV3.cs
```c#
public class GoogleRecaptchaV3 : StringInputViewModel
    {
        public string ApiKey { get; set; }

        public string ErrorMessage { get; set; }

        protected override void InitItemProperties(Item item)
        {
            base.InitItemProperties(item);

            ApiKey = Sitecore.StringUtil.GetString(item.Fields["Api Key"]);
            ErrorMessage = Sitecore.StringUtil.GetString(item.Fields["Error Message"]);
        }

        protected override void UpdateItemFields(Item item)
        {
            base.UpdateItemFields(item);

            item.Fields["Api Key"].SetValue(ApiKey, true);
            item.Fields["Error Message"].SetValue(ErrorMessage, true);
        }
    }
```
* Create custom validation class - CaptchaV3Validator.cs
```c#
public class CaptchaV3Validator : ValidationElement<string>
    {
        public override IEnumerable<ModelClientValidationRule> ClientValidationRules
        {
            get
            {
                if (string.IsNullOrEmpty(this.ApiKey))
                {
                    yield break;
                }
            }
        }

        protected virtual string ApiKey { get; set; }
        protected virtual string Title { get; set; }
        protected virtual string FieldName { get; set; }

        public CaptchaV3Validator(ValidationDataModel validationItem) : base(validationItem)
        {

        }

        public override void Initialize(object validationModel)
        {
            base.Initialize(validationModel);
            StringInputViewModel stringInputViewModel = validationModel as StringInputViewModel;
            if (stringInputViewModel != null)
            {
                var fieldItem = Sitecore.Context.Database.GetItem(ID.Parse(stringInputViewModel.ItemId));
                if (fieldItem != null)
                {
                    this.ApiKey = fieldItem["Api Key"];
                }
                this.Title = stringInputViewModel.Title;
                this.FieldName = stringInputViewModel.Name;
            }
        }

        public override ValidationResult Validate(object value)
        {
            if (value == null)
            {
                return new ValidationResult("Captcha is Inavlid.");// ValidationResult.Success;
            }
            var isCaptchaValid = ValidateCaptcha((string)value, this.ApiKey);
            if (!isCaptchaValid)
            {
                return new ValidationResult(this.FormatMessage(new object[] { this.Title }));
            }
            return ValidationResult.Success;
        }
        public static bool ValidateCaptcha(string response, string secret)
        {
            HttpClient httpClient = new HttpClient();

            var res = httpClient.GetAsync($"https://www.google.com/recaptcha/api/siteverify?secret=" + secret + "&response=" + response + "").Result;

            if (res.StatusCode != HttpStatusCode.OK)
                return false;

            string JSONres = res.Content.ReadAsStringAsync().Result;
            dynamic JSONdata = JObject.Parse(JSONres);

            if (JSONdata.success != "true")
                return false;

            return true;
        }
    }
```
* Create a View at location `Views/FormBuilder/FieldTemplates`- GoogleRecaptchaV3.cshtml
```c#
@using Sitecore.ExperienceForms.Mvc.Html
@model Glass.Mapper.Training.FormFields.GoogleRecaptchaV3


<input id="@Html.IdFor(m => Model.Value)" name="@Html.NameFor(m => Model.Value)" class="@Model.CssClass" type="hidden" value="" />

<script src="https://www.google.com/recaptcha/api.js?onload=grecaptcha_ready&render=@Model.ApiKey"></script>
<script>
    function grecaptcha_ready() {
        grecaptcha.ready(function () {
            grecaptcha.execute('@Model.ApiKey', { action: 'form' }).then(function (token) {
                document.getElementById("@Html.IdFor(m => Model.Value)").value = token;
            });
        });
    }
    var hiddenField = document.getElementById(@Html.Raw("\"" + Html.IdFor(m => Model.Value) + "\""));
	var parent = hiddenField.parentNode;
	if (parent.classList.contains("sc-formdesign-fieldcontainer")) {
		var textDiv = document.createElement("div");
		textDiv.innerHTML = "(ReCaptcha V3 Hidden Field)";
		parent.appendChild(textDiv);
	}
</script>
```

Let's move on to the sitecore item changes.

#### CORE db
* Create a form property by copying one of existing items ”SingleLineText” and rename the copied item as “GoogleReCaptchaV3”.
`/sitecore/client/Applications/FormsBuilder/Components/Layouts/PropertyGridForm/PageSettings/Settings/GoogleReCaptchaV3`

#### MASTER db
* In the Sitecore Content Editor, navigate to `/sitecore/templates/System/Forms/Fields`.
* Then add new template with name “CustomRecaptchaV3” and select Base template `/sitecore/templates/System/Templates/Template`
![alt text](https://dev-to-uploads.s3.amazonaws.com/i/ikegdblre9yrzh5ta6pb.png)
 
* This template must inherit as below
![alt text](https://dev-to-uploads.s3.amazonaws.com/i/8fidzjn6uz4qaowloglb.png)

* Create new Validation item at `/sitecore/system/Settings/Forms/Validations` as `CaptchaV3 Validation`.
![alt text](https://dev-to-uploads.s3.amazonaws.com/i/q0514sr5co5s04assn4p.png)

* Create new Field type at `/sitecore/system/Settings/Forms/Field Types/Security` with name `Google Recaptcha V3`.
![alt text](https://dev-to-uploads.s3.amazonaws.com/i/j622x30jhm1xj7y05oii.png)

o	View Path: `FieldTemplates/GoogleRecaptchaV3`
o	Model Type:  `<Namespace>.GoogleRecaptchaV3, <AssemblyName>`
o	Allowed Validations:  `CaptchaV3 Validation`
o	Property Editor: `Property Editor Settings/GoogleReCaptchaV3`
o	Field Template: `Fields/Google ReCaptcha V3`
o	Icon: `OfficeWhite/32x32/lock3.png`
o	BackgroundColor Color: `Tomato`
 
Now we are ready to use ReCaptcha V3 in Forms. Go to Sitecore Forms and simply drag and drop `Google ReCaptcha V3` field under `Security`.
![alt text](https://dev-to-uploads.s3.amazonaws.com/i/1rjzjoaiavorlfhib7ic.png)

That's it. The ReCaptcha V3 is ready!
![alt text](https://dev-to-uploads.s3.amazonaws.com/i/ynej3p37tpy45xpxsm9p.png)
 
> Note: reCAPTCHA v3 returns a score for each request without user friction. The score (between 0 and 1) is based on interactions with your site and you should update script to make decision based on the score according to your application needs. Also, I haven't included token validity but if the default 2 minutes is not enough, then you have to renew/refresh for every two minutes per google's documentation: https://developers.google.com/recaptcha/docs/verify#token_restrictions