Password Reset link Azure B2C Custom Policy - azure-ad-b2c

I have a custom policy that is working fine. However, noticed that the Password Reset (Forgotten Password) link is not showing. How do I get this to show, as we are also working on a custom ui for the policy as well.
I'm using the self asserted method.
<ContentDefinition Id="api.selfasserted">
<LoadUri>{Settings:CustomUIBaseUrl}/selfAsserted.html</LoadUri>
<RecoveryUri>~/common/default_page_error.html</RecoveryUri>
<DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:2.1.0</DataUri>
<Metadata>
<Item Key="DisplayName">Collect information from user page</Item>
</Metadata>
</ContentDefinition>
that's being referenced by this technical profile
<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="DisplayName">Signin</Item>
<Item Key="SignUpTarget">SignUpWithLogonEmailExchange</Item>
<Item Key="setting.operatingMode">Email</Item>
<Item Key="setting.forgotPasswordLinkLocation">AfterLabel</Item>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
<OutputClaim ClaimTypeReferenceId="password" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>

Use DATAURI: urn:com:microsoft:aad:b2c:elements:contract:unifiedssp:1.2.0 to have SignIn, SignUp and ForgotPassword in a single page.
When you click on Forgot Password you will get AADB2C90118 error code.
Handle Using Custom Policy:
https://github.com/azure-ad-b2c/samples/tree/master/policies/embedded-password-reset
If Using .Net then you can refer this link to handle the error code:
https://github.com/AzureADQuickStarts/B2C-WebApp-OpenIDConnect-DotNet-SUSI

Related

Why doesn't FormatLocalizedString work in Azure AD B2C custom policies?

I need to display a custom message after the code is sent in the password reset flow, I have tried following this https://learn.microsoft.com/en-us/azure/active-directory-b2c/string-transformations#formatlocalizedstring but it does not work. I am doing the following, very similar to the reference.
I add the same claimTransformation
<ClaimsTransformation Id="SetResponseMessageForOTPSent" TransformationMethod="FormatLocalizedString">
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
</InputClaims>
<InputParameters>
<InputParameter Id="stringFormatId" DataType="string" Value="ResponseMessage_EmailExists" />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="responseMsg" TransformationClaimType="outputClaim" />
</OutputClaims>
</ClaimsTransformation>
And the localized string
<LocalizedString ElementType="FormatLocalizedStringTransformationClaimType" StringId="ResponseMessage_EmailExists">Code sent to "{0}"</LocalizedString>
Finally I refer to the claimTransformation from a technicalProfile
<TechnicalProfile Id="SendOtp">
<DisplayName>Send Otp</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">Url</Item>
<Item Key="AuthenticationType">ApiKeyHeader</Item>
<Item Key="SendClaimsIn">Body</Item>
<Item Key="ContentDefinitionReferenceId">api.localaccountpasswordreset</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
</InputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="SetResponseMessageForOTPSent" />
</OutputClaimsTransformations>
</TechnicalProfile>
But it doesn't work, it always shows the message "Unable to validate the information provided". What am I doing wrong?

Calling secure REST API from Azure B2C custom policy to embed claims

I am trying to consume a Azure B2C secured API as part of the user journey by creating custom policies. I have created a claims provider to procure a bearer token as below
<ClaimsProvider>
<DisplayName>REST APIs</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="SecureREST-AccessToken">
<DisplayName></DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">https://***.b2clogin.com/***.onmicrosoft.com/B2C_1A_SignUpOrSignIn/oauth2/v2.0/authorize</Item>
<Item Key="AuthenticationType">Basic</Item>
<Item Key="SendClaimsIn">Form</Item>
</Metadata>
<CryptographicKeys>
<Key Id="BasicAuthenticationUsername" StorageReferenceId="B2C_1A_SecureRESTClientId" />
<Key Id="BasicAuthenticationPassword" StorageReferenceId="B2C_1A_SecureRESTClientSecret" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="client_credentials" />
<InputClaim ClaimTypeReferenceId="scope" DefaultValue="https://***.onmicrosoft.com/profileapi/profileapi-scope" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="bearerToken" PartnerClaimType="access_token" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
And another claims provider to call my secure REST API as below
<ClaimsProvider>
<DisplayName>REST APIs</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="AzureFunctions-GetRole">
<DisplayName>Get Roles </DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">https://***.azurewebsites.net/api/UserProfiles/CheckAdminUser</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="SendClaimsIn">Body</Item>
<Item Key="AllowInsecureAuthInProduction">false</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
<InputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email" />
<InputClaim ClaimTypeReferenceId="bearerToken"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="IsAdminUser" PartnerClaimType="IsAdminUser" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
How do I tie these two up? Should these be two steps in the user journey?
AAD B2C endpoint doesn’t support client credentials flow. Your initial call to get a token should model AAD client credentials flow:
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
You would call these technical profiles from the user journey if they return no possibility of an error to the user. Or otherwise as validation technical profiles referenced from a self asserted technical profile.

Azure B2C not sending email address as input claim to REST API validation service

I'm trying to retrieve claims from a REST API service as described in https://learn.microsoft.com/en-us/azure/active-directory-b2c/custom-policy-rest-api-claims-exchange. I'm trying to pass in the login email addres as an InputClaim along with another input claim (AzureTenantID). For some reason the API is always receiving the email InputClaim as empty. The other claim is populated, because it has a default value.
My understanding from the documentation is that this should work but for some reason it does not. Can anyone help me understand what I might be doing wrong? Do I have to specify a value for email?
My redacted technical profile is below. Thank you.
<TechnicalProfiles>
<!-- Custom Restful service -->
<TechnicalProfile Id="REST-API-ValidateEmail">
<DisplayName>Validate user's input data and return UserId claim</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">https://[servicename].azurewebsites.net/[methodname]</Item>
<Item Key="SendClaimsIn">Body</Item>
<!-- Set AuthenticationType to Basic or ClientCertificate in production environments -->
<Item Key="AuthenticationType">Basic</Item>
<!-- REMOVE the following line in production environments -->
<!--<Item Key="AllowInsecureAuthInProduction">true</Item>-->
</Metadata>
<CryptographicKeys>
<!-- B2C_1A_B2cRestClientId = WebServiceUser -->
<Key Id="BasicAuthenticationUsername" StorageReferenceId="B2C_1A_B2cRestClientId" />
<Key Id="BasicAuthenticationPassword" StorageReferenceId="B2C_1A_B2cRestClientSecret" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="AzureTenantId" PartnerClaimType="AzureTenantId" DefaultValue="[tenant].onmicrosoft.com" />
<InputClaim ClaimTypeReferenceId="email" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="UserId" PartnerClaimType="UserId" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
<!-- Change LocalAccountSignUpWithLogonEmail technical profile to support your validation technical profile -->
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="UserId" PartnerClaimType="UserId" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="REST-API-ValidateEmail" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
</TechnicalProfiles>
Please refer this GitHub link to Integrate REST API claims exchanges in your Azure AD B2C user journey to validate user input.
Technical profile
<ClaimsProvider>
<DisplayName>REST APIs</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="REST-ValidateProfile">
<DisplayName>Check loyaltyId Azure Function web hook</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">https://your-account.azurewebsites.net/api/ValidateProfile?code=your-code</Item>
<Item Key="SendClaimsIn">Body</Item>
<!-- Set AuthenticationType to Basic or ClientCertificate in production environments -->
<Item Key="AuthenticationType">None</Item>
<!-- REMOVE the following line in production environments -->
<Item Key="AllowInsecureAuthInProduction">true</Item>
</Metadata>
<InputClaims>
<!-- Claims sent to your REST API -->
<InputClaim ClaimTypeReferenceId="loyaltyId" />
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="userLanguage" PartnerClaimType="lang" DefaultValue="{Culture:LCID}" AlwaysUseDefaultValue="true" />
</InputClaims>
<OutputClaims>
<!-- Claims parsed from your REST API -->
<OutputClaim ClaimTypeReferenceId="promoCode" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
#Jas-Suri provided the correct answer in comments above. The proper claim to use in this scenario is signInName.

Custom Email verification in a single orchestration step in AD B2C Custom policies

I have a multi-step custom policy that first collects email from user and sends a verification code to the user when user clicks continue. The journey works fine. But the thing is validation of code is happening in next step. I need to bring that code validation in to the first orchestration step. I'm following the below doc to implement this journey:
"https://github.com/yoelhor/aadb2c-verification-code"
My technical profile is like the following:
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail-FirstStep">
<DisplayName>Email signup</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="IpAddressClaimReferenceId">IpAddress</Item>
<Item Key="ContentDefinitionReferenceId">api.localaccountsignup</Item>
<Item Key="language.button_continue">Send verification email</Item>
<Item Key="EnforceEmailVerification">False</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
<OutputClaim ClaimTypeReferenceId="verificationCode" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CopyEmailAsReadOnly" />
</OutputClaimsTransformations>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="REST-API-SendVerificationEmail" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
and the validation tech profile as follows:
<TechnicalProfile Id="REST-API-SendVerificationEmail">
<DisplayName>Sign-Up send link</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">https://myweb.azurewebsites.net/api/Identity/SendVerificationCode</Item>
<Item Key="AuthenticationType">None</Item>
<Item Key="SendClaimsIn">Body</Item>
<Item Key="AllowInsecureAuthInProduction">true</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="verificationCode" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
It cant be achieved currently, to call the REST API, the form must be submitted and that will cause the orchestration step to complete and move to the next one.
In a few weeks we will release how to achieve this, and without the use of an external REST API to generate and verify the OTP Codes. Stay tuned.

How to validate entered value is same as pre-defined value?

I am trying to verify that an email verification code entered by a user is same as one returned earlier by another technical profile. This journey step works as expected when the user enters the correct code but hangs when the user enters an incorrect code. What am I doing wrong. Here is the technical policy executed by my journey step:
<TechnicalProfile Id="EnterEmailVerifyCode">
<DisplayName>Email entry</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="IpAddressClaimReferenceId">IpAddress</Item>
<Item Key="ContentDefinitionReferenceId">api.localaccountsignup</Item>
<Item Key="language.button_continue">Continue</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="emailVerificationCodeEntered" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="emailVerificationCodeEntered" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="AssertEmailVerificationCodesAreEqual" />
</OutputClaimsTransformations>
</TechnicalProfile>
The self-asserted technical profile must invoke the claims transformation as a validation technical profile.
Declare a claims transformation technical profile that invokes the claims transformation:
<TechnicalProfile Id="ValidateEmailVerificationCodes">
<DisplayName>Validate Email Verification Codes</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<InputClaims>
<InputClaim ClaimTypeReferenceId="emailVerificationCodeEntered" />
<InputClaim ClaimTypeReferenceId="emailVerificationCodeGenerated" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="emailVerificationCodeEntered" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="AssertEmailVerificationCodesAreEqual" />
</OutputClaimsTransformations>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
Then invoke this claims transformation technical profile from the self-asserted technical profile as a validation technical profile:
<TechnicalProfile Id="EnterEmailVerifyCode">
...
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
...
<Item Key="UserMessageIfClaimsTransformationStringsAreNotEqual">The verification code is invalid</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="emailVerificationCodeEntered" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="emailVerificationCodeEntered" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="ValidateEmailVerificationCodes" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
UserMessageIfClaimsTransformationStringsAreNotEqual specifies the error message that is shown if the claims transformation raises errors.

Resources