Azure B2C Custom Policy to pre-populate the Fields in Sign Up page

Introduction

Azure B2C is a business to customer identity management as a service. Basically, using Azure AD B2C service, customer can use their social, and local account identities to get a SSO (Single sign on) access to your applications and APIs. This is a part of Azure B2C Custom policies series. I highly recommend visiting my previous blog on Azure B2C before going through this blog.

Recently while developing B2C solution, we came across a scenario where we need to check the user information from the external source based on the e-mail, if the user details are available pre-populate the fields during the registration, once the e-mail verification has been completed.

In this article I’m going to show how to configure our Azure B2C custom policies to pre-populate the GivenName, DisplayName and SurName based on the response from the REST API.

Pre-requests

  1. Azure B2C tenant
  2. Basic knowledge on XML
  3. Basic knowledge on Azure B2C custom policies

Create a Custom User Attribute

Before getting into custom policies, we need to create three custom user attributes in B2C.

Step 1: Login as Admin in Azure B2C tenant

Step 2: Create three custom user attributes, in my case I named it as customGivenName, displayName and customerName, as shown in below figure.

Custom user attributes

Please click here to learn more about custom user attributes.

Create a REST API

I have created a REST API using Azure functions to get a value for customDisplayName, customGivenName and customSurName

Azure Function – ValidateExternalUser

public static class ValidateExternalUser
    {
        [FunctionName("ValidateExternalUser")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            string name = req.Query["name"];

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data = JsonConvert.DeserializeObject(requestBody);
            string email = data?.email;
            ResponseContent r = new ResponseContent();          
            if (!string.IsNullOrEmpty(email) && email=="gowthamkk7@gmail.com") {            
            return (ActionResult)new OkObjectResult(new MSSQlIntegration.Model.ResponseContent()
            {
                extension_customDisplayName = "Gowtham K",
                extension_customGivenName="Gowtham",
                extension__customSurName="Kumar"
            });
            }
            else
            {
                return (ActionResult)new OkObjectResult(new MSSQlIntegration.Model.ResponseContent()
                {
                    extension_customDisplayName = "John Doe",
                    extension_customGivenName = "John",
                    extension__customSurName = "Doe"
                });
            }

        }
    }

The above azure function is called by custom policies, where the email sent through request body, and it returns ResponseContent model based on a condition.

Update the Custom Policy Extension file

I have used Azure B2C starter pack for this development and SignUpOrSignIn_SplitEmailVerificationAndSignUp extension file for this use case.

Open SignUpOrSignIn_SplitEmailVerificationAndSignUp.xml file using Visual Studio code.

Define the custom user attributes:

locate <ClaimsSchema> and add below code.

	<ClaimType Id="extension_customDisplayName">
				<DisplayName>Custom Display Name</DisplayName>
				<DataType>string</DataType>		

			</ClaimType>
			<ClaimType Id="extension_customGivenName">
				<DisplayName>Custom Given Name</DisplayName>
				<DataType>string</DataType>

			</ClaimType>
			<ClaimType Id="extension_customSurName">
				<DisplayName>Custom Sur Name</DisplayName>
				<DataType>string</DataType>

			</ClaimType>

Define Technical Profile:

Add a technical profile for the REST API call, locate the <Claims Providers> and add the below code.

	<ClaimsProvider>
			<DisplayName>REST APIs</DisplayName>
			<TechnicalProfiles>
				<TechnicalProfile Id="REST-GetProfile">
					<DisplayName>Get user extended profile 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>
						<!-- Set the ServiceUrl with your own REST API endpoint -->
						<Item Key="ServiceUrl">https://customclaimapp.azurewebsites.net/api/ValidateExternalUser?code=7QHUaWEJdtz6VrrJiEjaafZYXh_YSqibtKaRGeSOtq6TAzFuW4Byig==</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>
					   <Item Key="DebugMode">true</Item>
					</Metadata>
					<InputClaims>
						<!-- Claims sent to your REST API -->
						<InputClaim ClaimTypeReferenceId="email" />

					</InputClaims>
					<OutputClaims>
						<!-- Claims parsed from your REST API -->
						
						<!--<OutputClaim ClaimTypeReferenceId="extension_customDisplayName"/>-->
						<OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="extension_customDisplayName" Required="true" />
						<OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="extension_customGivenName" Required="true" />
						<OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="extension_customSurName" Required="true" />
						<!--PartnerClaimType="displayName"-->
					</OutputClaims>
					<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
				</TechnicalProfile>
			</TechnicalProfiles>
		</ClaimsProvider>

The above technical profile will do a REST API call. In my case it is an Azure function. The email address entered by the user is send as an input through body of the request and response value will be mapped to custom user attributes as an output claim.

Locate <EmailVerification> tecnical profile and add the below code

<TechnicalProfiles>
				<!--Email verification only-->
				<TechnicalProfile Id="EmailVerification">
					<DisplayName>Initiate Email Address Verification For Local Account</DisplayName>
					<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
					<Metadata>
						<Item Key="ContentDefinitionReferenceId">api.localaccount.emailVerification</Item>
						<Item Key="language.button_continue">Continue</Item>
					</Metadata>
					<OutputClaims>
						<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />						
					</OutputClaims>
					<ValidationTechnicalProfiles>
						<ValidationTechnicalProfile ReferenceId="REST-GetProfile" />
					</ValidationTechnicalProfiles>
				</TechnicalProfile>

Define ClaimTransformations:

Locate <ClaimTransformations> and add the code below

<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="REST-GetProfile" />
</ValidationTechnicalProfiles>

The above ValidationTechnicalProfile will invoke the REST-GetProfile technical profile once the email verification completes and user click on continue button.

<ClaimsTransformation Id="CreateReadonlyDisplayNameClaim" TransformationMethod="FormatStringClaim">
				<InputClaims>
					<InputClaim ClaimTypeReferenceId="displayName" TransformationClaimType="inputClaim" />
				</InputClaims>
				<InputParameters>
					<InputParameter Id="stringFormat" DataType="string" Value="{0}" />
				</InputParameters>
				<OutputClaims>
					<OutputClaim ClaimTypeReferenceId="extension_customDisplayName" TransformationClaimType="outputClaim" />
				</OutputClaims>		
				</ClaimsTransformation>
			<ClaimsTransformation Id="CreateReadonlyGivenNameClaim" TransformationMethod="FormatStringClaim">
				<InputClaims>
					<InputClaim ClaimTypeReferenceId="givenName" TransformationClaimType="inputClaim" />
				</InputClaims>
				<InputParameters>
					<InputParameter Id="stringFormat" DataType="string" Value="{0}" />
				</InputParameters>
				<OutputClaims>
					<OutputClaim ClaimTypeReferenceId="extension_customGivenName" TransformationClaimType="outputClaim" />
				</OutputClaims>		
				</ClaimsTransformation>
			<ClaimsTransformation Id="CreateReadonlySurNameClaim" TransformationMethod="FormatStringClaim">
				<InputClaims>
					<InputClaim ClaimTypeReferenceId="surName" TransformationClaimType="inputClaim" />
				</InputClaims>
				<InputParameters>
					<InputParameter Id="stringFormat" DataType="string" Value="{0}" />
				</InputParameters>
				<OutputClaims>
					<OutputClaim ClaimTypeReferenceId="extension_customSurName" TransformationClaimType="outputClaim" />
				</OutputClaims>
			</ClaimsTransformation>

The above code will transform the input claims, this will be use as a part of user journey.

Update LocalAccountSignUpWithReadOnlyEmail Technical profile

Under LocalAccountSignUpWithReadOnlyEmail technical profile locate <InputClaimsTransformations> and add the below code.


	<InputClaimsTransformation ReferenceId="CreateReadonlyDisplayNameClaim" />
	<InputClaimsTransformation ReferenceId="CreateReadonlyGivenNameClaim" />
	<InputClaimsTransformation ReferenceId="CreateReadonlySurNameClaim" />

This will invoke the input claim transformation, that we defined in previous step.

Locate <InputClaims> and add below code.

<InputClaim ClaimTypeReferenceId="displayName" />
<InputClaim ClaimTypeReferenceId="givenName" />
<InputClaim ClaimTypeReferenceId="surName" />			

This will pre-populate the values in the text box during signup.

Azure B2C Sign Up

Summary

We have seen how to integrate the REST API into email verification step to get the user details and pre-populate the user details (displayName, firstName and surName) in Sign Up page.

Download source – click here

gowthamk91

Leave a Reply

%d