Menu

Key findings and learnings of Azure AD B2C custom policy configuration with federated authentication

Background

I recently worked in the project where we implemented an application which uses Azure AD B2C as an IDP. In the first phase users were using local Azure AD B2C to sign up and sign in. Next phase of project brought federated external IDP sign in possibility for the users. This blog post shows how federated sign in with OpenIdConnect based IDP is configured by using Identity Experience Framework (custom policy). In the end of the post I'll write a little bit about key findings & learnings and challenges related to custom policies.

undefined

What are Azure AD B2C custom policies?

Custom policies enable you to modify authentication flow based on your complex authentication requirements. With custom policies you have full control of life cycle of the authentication flow, what claims to return, how to transformation and enrich claims. It is also possible to execute external API requests during the authentication flow. Custom policy configurations are modelled to the XML-files. Custom policies require to configure several XML files which have references to each other in a hierarchical chain. Before starting you should familiar yourself with custom policy samples which can be found from GitHub.

Alternative for custom policy is user flows which can be configured directly from the Azure Portal. User flows allows you to configure most common identity tasks for your applications ex. social media platform authentication, common claim handling, MFA and layout customization. 

More details about user flows and custom policies:

Custom policies in Azure Active Directory B2C

User flows in Azure Active Directory B2C

Azure Active Directory B2C: Custom CIAM User Journeys

You should remember that Microsoft recommends to use out of the box user flows when ever it's possible. Custom policies are designed primarily for complex authentication scenarios.

Configuration of federated authentication

Next let's go through steps what should do when configurating federated authentication with custom policies.

Sign in flow sequence diagram

undefined

1) Configure client to the third party IDP

Configurate IDP client to the third party IDP by using authorization code flow. You have to configure ClientId, Client Secret and Scopes for the client. Later these will be configured to the Azure AD B2C custom policy XML-file.

2) Configure third party IDP client's secret to the Azure AD B2C

Client secret what you got in the previous phase should be configured as a signing key to the Policy Keys under Identity Experience Framework in Azure AD B2C.

3) Claims provider configuration

Claims Provider configuration in TrustFrameworkExtensions.xml file determines third party IDP settings.

Metadata

Metadata section configurates communication parameters of the third party OpenIdConnect IDP and client. Metadata is a list of key value pairs. Check all available configuration keys from here.

CryptographicKeys

Azure AD B2C has a feature which enables you to store secrets and certificates. This feature is knows as "Policy keys". You can modify policy keys directly from the Azure AD B2C management view in Azure Portal. In this case we configure third party IDP client's secret to the policy keys as a signing key. During the technical profile executing, Azure AD B2C retrieves the cryptographic keys from Azure AD B2C policy keys.

OutputClaims

The OutputClaims element configures and maps claims which are returned from the third party IDP.

OutputClaimsTransformations

The OutputClaimsTransformations configures how output claims are modified or new claims generated. This example follows social login sample so UPN and Alternative Security Id is generated based on sub value returned by third party IDP.

<ClaimsProvider>
      <Domain>thirdparty.idp.fi</Domain>
      <DisplayName>Third party IDP</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="IDP-OAUTH">
          <DisplayName>IDP</DisplayName>
          <Protocol Name="OpenIdConnect" />
          <Metadata>
            <Item Key="ProviderName">IDP</Item>
            <Item Key="METADATA">https://thirdparty.idp.fi/.well-known/openid-configuration</Item>
            <Item Key="ValidTokenIssuerPrefixes">https://thirdparty.idp.fi</Item>
            <Item Key="IdTokenAudience">services.clientId</Item>
            <Item Key="DiscoverMetadataByTokenIssuer">true</Item>
            <Item Key="response_types">code</Item>
            <Item Key="response_mode">form_post</Item>
            <Item Key="scope">openid given_name family_name name phone_number email address</Item>
            <Item Key="HttpBinding">POST</Item>
            <Item Key="UsePolicyInRedirectUri">false</Item>
            <Item Key="client_id">services.clientId</Item>
            <Item Key="SingleLogoutEnabled">true</Item>
          </Metadata>
          <CryptographicKeys>
            <Key Id="client_secret" StorageReferenceId="B2C_1A_IDPCLIENTSECRET" />
          </CryptographicKeys>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="sub" />
            <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />
            <OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="family_name" />
            <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="federatedAuthentication" />
            <OutputClaim ClaimTypeReferenceId="identityProvider" PartnerClaimType="iss" />
            <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
            <OutputClaim ClaimTypeReferenceId="phone_number" PartnerClaimType="phone_number" />
            <OutputClaim ClaimTypeReferenceId="address" PartnerClaimType="address" />
            <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
          </OutputClaims>
          <OutputClaimsTransformations>
            <OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" />
            <OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" />
            <OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" />
          </OutputClaimsTransformations>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin" />
        </TechnicalProfile>
      </TechnicalProfiles>
</ClaimsProvider>

4) User Journey configuration

User Journey determines all steps "business logic" which are executed during the authentication flow. The ClaimsProviderSelections element determines which authentication providers are visible for user in sign in view in Azure AD B2C. In this case IDPExchange is the new third party IDP. Orchestration step 2 must contain reference to the IDPExchange which was declared in the first step.

Note! sample below does not contain all required orchestration steps.

<UserJourney Id="SignUpOrSignInWithFederation">
      <OrchestrationSteps>
        <OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
          <ClaimsProviderSelections>
            <ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
            <ClaimsProviderSelection TargetClaimsExchangeId="IDPExchange" />
          </ClaimsProviderSelections>
          <ClaimsExchanges>
            <ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="2" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
              <Value>objectId</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonEmail" />
            <ClaimsExchange Id="IDPExchange" TechnicalProfileReferenceId="IDP-OAUTH" />
          </ClaimsExchanges>
        </OrchestrationStep>
</UserJourney>

Key findings and learnings

1) Federated sign out to third party OpenIdConnect IDP is not complete

undefined

Azure AD B2C does not relay Id token to the end session endpoint of the third party IDP. According to OpenIdConnect specs it's a recommendation that Id token should be relayed but Azure AD B2C does not support this right now. I also got confirmation about that from the MS support.

It's also important that SingleLogoutEnabled is configured to true in the ClaimsProvider configuration otherwise federated sign out is not executed.

<Item Key="SingleLogoutEnabled">true</Item>

In our project this was an issue because the third party IDP required the Id token to finalize complete sign out. We had to made some modifications to the third party IDP which enabled smooth sign out user experience even Id token was not relayed.

2) Usage of acr_values parameter

OpenId Connect protocol allows you to send custom parameters to the authorization endpoint by using acr_values parameter. If you need to deliver custom static parameters to the third party IDP you can determine acr_values as a Input Claim in the claims provider configuration.

<InputClaims>
	<InputClaim ClaimTypeReferenceId="acr_values" DefaultValue="custom1:Parameter1 custom2:Parameter2" />
</InputClaims>

3) Preconditions are handy way to set conditions

Preconditions inside ex. orchestration step allows you to control is the step executed or not. For example you can configure that MFA step is not executed if specific claims conditions are fulfilled. 

<OrchestrationStep Order="9" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
              <Value>authenticationSource</Value>
              <Value>federatedAuthentication</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="PhoneFactor-Verify" TechnicalProfileReferenceId="PhoneFactor-InputOrVerify" />
          </ClaimsExchanges>
        </OrchestrationStep>

4) Claim resolvers

Claim resolvers in Azure AD B2C custom policies provide context information such as the policy name, request correlation ID, user interface language, and more. Especially very useful claim resolver is {oauth2:access_token} which allows to relay user's access token of third party IDP to calling application. More info about claim resolvers.

5) Application insights for troubleshooting

Azure AD B2C has a feature which enables to send data to the Application Insights. Application Insight integration is a must have thing because it really helps you in troubleshooting situations. This Microsoft article shows how to configure Application Insights for troubleshooting. Custom policies also supports Application insight custom events which can be configured to the User Journey flow. 

6) DevOps automation

Azure AD B2C deployment and configuration can be fully automatized with Azure DevOps. I'll write an other blog post about that how we did it in the project.

7) Tools

Visual Studio Code has Azure AD B2C custom policy extension which allows you quickly navigate through Azure AD B2C custom policies. You can also create elements like technical profiles and claim definitions.

undefined

undefined

Summary

Azure AD B2C is a very powerful and scalable identity management solution for B2C cases. Identity Experience Framework (custom policy) configuration might first feel pretty complex "legacy" way to configure things in XML files but eventually it's a very extendable and powerful way to handle even complex authentication scenarios. I first tested out of the box user journey but quite soon I realized that it's too simple and limited so only real option is custom policies. Azure AD B2C has some limitations like federated sign out issue which I covered earlier in this blog post but overall I'm going to use Azure AD B2C for other projects as well.  

Comments