Enhancing Azure AD B2C Behavior with Custom Policies

Scott Lusk
Hitachi Solutions Braintrust
12 min readApr 26, 2020
Azure Active Directory B2C

Introduction

Are you are using, or even plan to use, Azure Active Directory B2C for Identity and access management in your apps? If so, then it is likely you will encounter situations where you will want to modify default behaviors or provide additional claims with the JSON Web Tokens (JWT) that AAD B2C generates that just aren’t available out of the box for this Azure service. Luckily, AAD B2C provides some custom capabilities that enable you to extend this service and supplement generated JWTs with the information you need for identity and access management purposes specific to your app needs.

Before we go any further, if you are entirely new to Azure Active Directory B2C then I recommend you pause for a moment and start by checking out the product details page at azure.microsoft.com and then move on to the Azure Active Directory B2C documentation. The What is Azure Active Directory B2C? documentation provides a good overview to get started with as well.

As a quick reminder for everyone though, let’s look at what the description the What is Azure Active Directory B2C? documentation provides us:

Azure Active Directory B2C provides business-to-customer identity as a service. Your customers use their preferred social, enterprise, or local account identities to get single sign-on access to your applications and APIs.

Azure Active Directory B2C (Azure AD B2C) is a customer identity access management (CIAM) solution capable of supporting millions of users and billions of authentications per day. It takes care of the scaling and safety of the authentication platform, monitoring and automatically handling threats like denial-of-service, password spray, or brute force attacks.

Focus for this article

There are a few different areas in which you can customize the out of the box experience with AAD B2C. This article will focus only on the area of Custom Policies; in future articles I will speak to use of Custom Attributes and other capabilities that are available when working with Azure AD B2C. For clarification though, below is a definition of Custom Policies and Custom Attributes, since it’s important to be aware of both.

Custom Policies

Custom policies are configuration files that define the behavior of your Azure Active Directory B2C (Azure AD B2C) tenant. User flows are predefined in the Azure AD B2C portal for the most common identity tasks. Custom policies can be fully edited by an identity developer to complete many different tasks.

Custom Attributes

Azure AD B2C directory comes with a built-in set of attributes. However, you often need to create your own attributes to manage your specific scenario.

Sample Repository

There is a sample GitHub repository here that can be used to follow along with this article and act as a guide in getting started.

Scenario

There are a lot of different ways you may approach this with your apps but the underlying concepts of customizing AAD B2C behavior will be the same, and that is what I will focus on in this article. In the example repository itself that is referenced in this article, the following setup will be used for demonstration:

  • Azure Active Directory B2C Tenant: for identity and access management
  • Azure Function App: REST endpoint for REST technical profile to call into for claims exchange
  • Blazor Server App: application for Login to B2C and demo of generated JWT
  • Custom Policy Files: XML files used to customize B2C and define behaviors
  • Provisioning Scripts: for deploying resources to Azure

Getting Started

B2C Tenant

The very first thing you will need to get started is an Azure Active Directory B2C tenant. Follow the tutorial at Create an Azure Active Directory B2C tenant to stand one up quickly if you do not already have one. When you are finished with your tenant and need to get rid of it, I found this article How to REALLY delete an Azure Active Directory B2C tenant very helpful.

App Registration

Next, if you are following along with the sample repository or you have your custom app you plan to use to authenticate with your B2C tenant, then you will need to create an app registration. To set this up follow the steps at Register an application in Azure Active Directory B2C. You can set up some sample User Flows by following the instructions at Create user flows in Azure Active Directory B2C, but these are the out of the box examples and this article’s focus is on custom policy.

Custom Policies

Now, let’s dive into what it takes to create a custom policy. As mentioned earlier, custom policies are configuration files that define the behavior of your AAD B2C tenant. These come in the form of XML files that you can make changes to and then upload to the Identity Experience Framework (IEF) in your AAD B2C tenant.

Getting started with custom policies

The starting point for this is outlined at: Get started with custom policies in Azure Active Directory B2C. If you follow along in that document it will have you perform the following steps:

If the steps above could be automated that would be the preferred approach. From what I’ve read this may be coming via AzureADPreview but last I checked some of this functionality still was not supported for AAD B2C, only AAD. Hopefully in the near future I can update this article or provide another that will go over how to automate this process rather than doing it by hand. If you have experience in automating any parts of this I would love to hear about your experience.

Custom policy files

If you focus on anything in this article, focus on this. The custom policy starter pack is the best place to spend your time digging into and gaining a better understanding of how to work with custom policies, outside of everything else. This is at the heart of this concept and a good understanding of the policy files is essential. Custom policies are configuration files that define the behavior of your AAD B2C tenant. It gives you some flexibility in defining the behavior you would like to see.

It should be noted that when it comes to defining policies in AAD B2C you will either take the route of creating User flows or Custom policies. Anytime you are issuing a request to AAD B2C such as Sign Up, Sign In, Edit Profile, or Reset Password you have to specify which policy (Relying Party File) your AAD B2C tenant needs to use to complete that operation. As a result, you will have to choose whether the policy you specify is one created from a User flow OR a Custom policy. It is worth noting, however, that even the User flows themselves utilize this same approach. But it simplifies the process for you by removing the need to interact directly with the policy files; rather it uses some canned pre-made common examples.

After downloading the starter pack, take some time to become acquainted with the code. The starter pack comes with a few different examples, but the Getting started documentation and the sample repository referenced in this article use the SocialAndLocalAccounts example.

It’s worth taking a moment to understand the types of policy files you will see in the starter pack. As noted in the documentation:

Base file — contains most of the definitions. It is recommended that you make a minimum number of changes to this file to help with troubleshooting and long-term maintenance of your policies.

Extensions file — holds the unique configuration changes for your tenant.

Relying Party (RP) file — The single task-focused file that is invoked directly by the application or service (also, known as a Relying Party). Each unique task requires its own RP and, depending on branding requirements, the number might be “total of applications x total number of use cases.”

In the starter pack an example of each is as follows:

  • Base file — TrustFrameworkBase.xml
  • Extensions file — TrustFrameworkExtensions.xml
  • Relying Party (RP) file — SignUpOrSignin.xml

As you work with the custom policy files, you’ll notice names such as UserJourneys, RelyingParty, ClaimsProviders, TechnicalPofiles, and so on. If you want to take a deeper dive into each of those I recommend starting with the details outlined at TrustFrameworkPolicy documentation and follow some of the links available there.

Here are are a few very brief descriptions of each as taken from the documentation:

UserJourney — User journeys specify explicit paths through which a policy allows a relying party application to obtain the desired claims for a user.

RelyingParty — The RelyingParty element specifies the user journey to enforce for the current request to Azure Active Directory B2C (Azure AD B2C). It also specifies the list of claims that the relying party (RP) application needs as part of the issued token.

ClaimsProviders — A claims provider contains a set of technical profiles. Every claims provider must have one or more technical profiles that determine the endpoints and the protocols needed to communicate with the claims provider.

TechnicalProfiles — A TechnicalProfiles element contains a set of technical profiles supported by the claims provider. Every claims provider must have one or more technical profiles that determine the endpoints and the protocols needed to communicate with the claims provider.

Claims Providers

With Azure AD B2C, by default, you can utilize Local Sign Up/Sign In to authenticate users via an email address or user name as stored in Azure AD B2C, along with maintaining their identity information. In most cases however, you may want to sign in with other identity providers external to AAD B2C. In AAD B2C you use Identity Providers to enable sign in with these external identity providers. Identity providers create, maintain, and manage identity information while also providing authentication services to applications.

When it comes to working with Custom Policies, you utilize what is referred to as a ClaimsProvider that contains a set of technical profiles that determine the endpoints and protocols necessary to communicate with an external identity provider.

In the Microsoft documentation there are various examples of how to set up ClaimsProviders to talk to various OIDC/OAuth providers or SAML providers. To name a few:

For example, in the sample repository TrustFrameworkExtensions.xml file you will find this example of connecting to Azure AD (Single-tenant) in the ClaimsProviders sections. For more details on how this works, you can follow the instructions at Azure Active Directory (Single-tenant) to create this.

In the example below, note the following sections:

  • Metadata — identifies how to connect to the identity provider
  • CryptographicKeys — contains client secret passed to identity provider when connecting
  • OutputClaims — any output claims you expect to receive from the provider once an identity is verified
  • OutputClaimsTransformations — any transformations applied to the provided output claims
Azure AD (single-tenant) ClaimsProvider

To hook up the ClaimsProvider you have to add it to the ClaimsExchanges section of a UserJourney. In the sample below, note everywhere that OIDC-AZURE-AD is used, as this points to the Technical Profile that is contained in the Azure AD ClaimsProvider we just looked at in the example above.

In this example you’ll see there are three different ClaimsProviders supported (see ClaimsProviderSelections section):

  • Facebook
  • Azure AD (single-tenant)
  • Local account sign in with email
Hook up ClaimsProvider in a UserJourney

Claims Exchanges and Custom Business Logic

After setting up Claims Providers you also may need to set up various claims exchanges. A common scenario for this would be when you want to implement your own business logic into a user journey. Claims exchanges offers you the ability to hook into your user journey and obtain additional claims validation or claims enrichment. An example of this that you will see in the Microsoft documentation is how to Integrate REST API claims exchanges in your Azure AD B2C custom policy.

This approach is simple enough to set up and gives you some flexibility in providing your own REST endpoint that can receive various input claims and provided output claims that get added to the generated JWT token. The good news is that you control the REST API side of it entirely, which gives you complete control and flexibility over what is used to enrich or validate your claims. For example, perhaps you have a data store that, given a user identity, can look up additional items you want to include as claims when the user signs into the application.

Follow the documentation for the full walk-through, but ultimately the end result is a ClaimsProvider that connects to your REST API, an example shown below, and is available in the sample repository TrustFrameworkExtensions.xml file.

It’s important to note that any InputClaim or OutputClaim that you expect to send/receive from the REST API must also be defined in the BuildBlocks ClaimsSchema or IEF won’t recognize the claim. This is shown in the example below as well. In the UserJourney orchestration steps, Step 7 is where you will see the exchange occur to call into the REST API.

In addition to claims exchange this type of profile can also be used as a Validation Technical Profile to validate things such as user input during the sign-up process. See documentation for more details on validation technical profiles.

Note the following:

  • BuildingBlocks — defines the Claims Schema for any input or output claims used by the claims provider
  • ClaimsProvider — identifies the REST API endpoint used for claims exchange
  • UserJourney — hooks up a ClaimsExchange to call into the REST API
ClaimsExchange using a REST API

If going the route of adding your own business logic is the path you want to take, I recommend spending some time in the following related documentation:

Security considerations for claims exchanges

If you are using a claims provider in a custom policy you will want to make sure that your endpoints are secure and protected. In the example in the previous section using a REST API for claims exchanges, you may have noticed that the AuthenticationType was set to None for the REST API ClaimsProvider. Though this can sometimes be useful in a dev environment you NEVER want this to be the case for a production environment or any environment exposed publicly. Be certain to take the necessary steps to secure your endpoints. If you followed the documentation on how to integrate with the REST API you will have noticed a section on security considerations.

As of this writing there are three options available for authenticating with your endpoint (e.g. REST API) when using them with Azure AD B2C custom policies:

I’ve typically chosen to go the route of using a client certificate, since this is fairly typical for most implementations of REST endpoints anyway. Bearer is appealing, but as of this writing that approach is still in preview.

Troubleshooting

When it comes to troubleshooting anything written in the custom policy files there will be two areas that will be of assistance.

The first to be aware of is outlined in the article on Troubleshoot Azure AD B2C custom policies and Identity Experience Framework. When you upload a custom policy file into IEF it will perform validation for you and indicate whether there are any issues with the policy file. Understanding some of the common causes of issues can make troubleshooting and authoring a little easier.

Secondly, application insights can be your friend when it comes to trying to troubleshoot a policy that may have passed validation but seems to fail when you try to use it at runtime. The article Collect Azure Active Directory B2C logs with Application Insights goes into detail on how you can set this up.

Summary

The intent of this article is to introduce you to the concept of custom policies and give you just enough taste of what’s involved to allow you to determine whether this is an area you want to explore further. Keep in mind the NOTE that the Microsoft documentation points out in nearly all of the custom policy articles:

In Azure Active Directory B2C, custom policies are designed primarily to address complex scenarios. For most scenarios, we recommend that you use built-in user flows.

That being said, custom policies may not always be the best fit for your implementation and do require extra work to get them up and going. The great news is that if this is the route you need to take for your projects, AAD B2C gives you this option.

My intent in an article such as this is to never go into every single step involved, as there is already existing documentation that does a good job of that. I hope that the references I’ve provided and the additional guidance helps you as you get started.

Check out the links below for further reading and of course check out the sample repository I’ve provided. I plan to write more articles on the topic of Azure AD B2C in the near future. Happy coding and please reach out if you have any questions I can answer.

References and Further Reading

As I dug through this topic I found several links that provided guidance. I’ve noted some of them below. The goal of this article has been to reduce the number of places someone would have to look to find such guidance.

--

--