I try to add a reCaptcha on my signin page using custom policies. How can I add a Google reCaptcha field to my custom signin page that is based on the "unified.html" template? I need it to be able to validate the code inside the policy ValidationTechnicalProfile so it has to come back from the UI.
I started off with this sample which works with an OrchestrationStep with ContentDefinitionReferenceId="api.selfasserted" (based on a selfasserted page). In this sample, the code comes from a custom field "g-recaptcha-response-toms" so I added this claim to our code. But there is no way to have it render by the engine.
On our own policy, the first step is this one. Note that the ContentDefinitionReferenceId is "api.signuporsignin" :
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Username" />
</ClaimsExchanges>
</OrchestrationStep>
The "api.signuporsignin" content definition points to a unifiedssp contract. And "UnifiedCustomUrl" is a blob storage url to our own cutom page, based on "unified.html" page from Microsoft templates.
<ContentDefinition Id="api.signuporsignin">
<LoadUri>{Settings:UnifiedCustomUrl}</LoadUri>
<RecoveryUri>~/common/default_page_error.html</RecoveryUri>
<DataUri>urn:com:microsoft:aad:b2c:elements:contract:unifiedssp:2.1.5</DataUri>
<Metadata>
<Item Key="DisplayName">Signin and Signup</Item>
</Metadata>
</ContentDefinition>
Now our technical profile "SelfAsserted-LocalAccountSignin-Username" is this one :
<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Username">
<DisplayName>Local Account Signin</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="setting.showSignupLink">False</Item>
<Item Key="setting.showCancelButton">False</Item>
<Item Key="setting.forgotPasswordLinkLocation">AfterInput</Item>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
<Item Key="UserMessageIfClaimsTransformationStringsAreNotEqual">The last names you provided are not the same</Item>
<Item Key="AllowGenerationOfClaimsWithNullValues">true</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" DefaultValue="{OIDC:LoginHint}" />
<InputClaim ClaimTypeReferenceId="g-recaptcha-response-toms" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
<OutputClaim ClaimTypeReferenceId="password" Required="true" />
<OutputClaim ClaimTypeReferenceId="g-recaptcha-response-toms" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
<OutputClaim ClaimTypeReferenceId="isEmailBoolean" />
<OutputClaim ClaimTypeReferenceId="errorCode" Required="true" DefaultValue="1234" />
<OutputClaim ClaimTypeReferenceId="errorMessage" Required="true" DefaultValue="Error message to return" />
<OutputClaim ClaimTypeReferenceId="isDevlopmentEnvironment" DefaultValue="{Settings:UseFakeEmailForTests}" AlwaysUseDefaultValue="true" />
</OutputClaims>
<ValidationTechnicalProfiles>
<!-- Validates Google reCaptcha -->
<ValidationTechnicalProfile ReferenceId="login-Recaptcha" />
<!-- Initiate a normal logon against Azure AD B2C -->
<ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
I asked this question on the Microsoft Q&A forum. The answer is there. https://learn.microsoft.com/en-us/answers/questions/1165949/aad-b2c-add-recaptcha-to-signin-page-with-custom-p
But I will copy the summarization by the Microsoft employee here, just in case link gets broken in the future :
Marilee Turscak-MSFT Microsoft Employee Feb 3, 2023, 5:29 PM Hi Patrice Côté ,
I'm glad that you were able to resolve your issue and thank you for posting your solution so that others experiencing the same thing can easily reference this! Since the Microsoft Q&A community has a policy that "The question author cannot accept their own answer. They can only accept answers by others ", I'll repost your solution in case you'd like to "Accept " the answer.
Issue:
You wanted to add a reCaptcha on your signin page using custom policies in Azure AD B2C. You were using the sample A B2C IEF Custom Policy which integrates with Google Captcha
You ran into two main issues:
When adding the custom field "g-recaptcha-response-toms", it would not render. After you were able to resolve the first issue and get the information in the form, the "Forgot password" link would not display. Solution:
Updating the the page contract from "unifiedssp:2.1.5" to "selfasserted:2.1.9" page layout version resolved the issue of not being able to gather the information on the form. To add the "Forgot password" link, you had to create it on page load with JavaScript (see similar example with Terms of Use link):
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const login_hint = urlParams.get("login_hint");
const ui_locales = urlParams.get("ui_locales");
const state = urlParams.get("state");
const redirect_uri = urlParams.get("redirect_uri");
document.getElementById("login_hint").innerHTML = login_hint;
const forgotPassurl = ""+redirect_uri+"#error=access_denied&error_description=AADB2C90118%0d%0alogin_hint="+login_hint+"%0d%0a&state="+state+"&lang="+ui_locales+"";
if(ui_locales == "fr") {
document.getElementById('recaptchaScript').src = document.getElementById('recaptchaScript').src+"?hl=fr";
document.getElementById("forgotPassword").innerHTML = "Mot de passe oublié ?";
}
else {
document.getElementById('recaptchaScript').src = document.getElementById('recaptchaScript').src+"?hl=en";
document.getElementById("forgotPassword").innerHTML = "Forgot your password ?";
}
document.getElementById("forgotPassword").href = forgotPassurl;
If you have any other questions or run into more issues with the sample, please let me know.
Thank you again for your time and patience throughout this issue.