Pushing Azure AD B2C Custom Policies Through GitHub Actions Using Federated Credentials
Published Jun 15 2022 09:00 AM 4,920 Views
Iron Contributor

I have been using Azure AD B2C for a couple years now, and I'm mostly happy with the product. (A little complexity is what makes things fun.) When the built-in user flows don't cut it you have to create custom policies based on XML, but it has been a somewhat bumpy ride getting the custom policies you craft uploaded to Azure. In the beginning you could only do it through the Azure Portal which made for a manual and error-prone deployment process. After a couple of interim improvements along the way we have eventually gotten to where it's possible to have an Azure DevOps based pipeline setup  invoking REST APIs to get the policies into the right place. It's not perfect though so I thought I'd take a crack at improving further upon this.


The current API for uploading policies is the Graph API, but the tooling has been substandard compared to other Azure services. Fortunately there are some new (albeit horribly documented) PowerShell cmdlets for the TrustFramework. They need to be tested.


Since I've been working through the various ways to use Federated Credentials lately I figured it should be possible to use this for Azure AD B2C tenants as well - spoiler alert; yes it is. It means we will be using GitHub for source code and GitHub Actions for deployment as Azure DevOps is not in target for this type of authentication currently.


This is not a post about Azure AD B2C in general, so there are some pre-reqs and shortcuts.


You need to have a working B2C tenant already. And you should probably have dabbled with B2C to understand what this is all about as well.



You should perform the configuration steps (creating keys and registering apps) described here:



I used the SocialAndLocalAccounts policies from the Custom Policy Starter Pack:




The steps for configuring Azure AD to trust GitHub repos also works for B2C so follow the instructions here to set this up:



Make sure the app has the Policy.ReadWrite.TrustFramework Application permission (and that you perform the admin consent in the portal):



In the GitHub repo you created you should create some Environment secrets:



The values are as follows:

AZURE_CLIENT_ID => The clientId of the app you registered in #2.

AZURE_TENANT_ID => TenantId of the B2C tenant. Can also be copied based on #2.


B2C_IEF_APPID => The clientId of the IdentityExperienceFramework application in #1.

B2C_PROXY_IEF_APPID => The clientId of the ProxyIdentityExperienceFramework application in #1.


B2C_TENANT_NAME => The string representation of the tenant. This would be "Contoso" if your tenant is contoso.onmicrosoft.com.


The policies are generic and the correct values are swapped in on deploy so to account for this I made some tweaks to make the substitution easier. For instance:

yourtenant.onmicrosoft.com => ${B2C_TENANT_NAME}.onmicrosoft.com


Piecing together the workflow there are three parts:

Connecting to Azure


- name: 'Az CLI login'
  uses: azure/login@v1
    client-id: ${{ secrets.AZURE_CLIENT_ID }}
    tenant-id: ${{ secrets.AZURE_TENANT_ID }}
    allow-no-subscriptions: true
    enable-AzPSSession: true



Replacing values


- name: Replace placeholder values
  run: |
    sed -i 's|${B2C_TENANT_NAME}|${{ secrets.B2C_TENANT_NAME }}|g' ./policies/TrustFrameworkBase.xml
    sed -i 's|${B2C_TENANT_NAME}|${{ secrets.B2C_TENANT_NAME }}|g' ./policies/TrustFrameworkLocalization.xml
    sed -i 's|${B2C_TENANT_NAME}|${{ secrets.B2C_TENANT_NAME }}|g; s|${B2C_PROXY_IEF_APPID}|${{ secrets.B2C_PROXY_IEF_APPID }}|g; s|${B2C_IEF_APPID}|${{ secrets.B2C_IEF_APPID }}|g' ./policies/TrustFrameworkExtensions.xml
    sed -i 's|${B2C_TENANT_NAME}|${{ secrets.B2C_TENANT_NAME }}|g' ./policies/SignUpOrSignin.xml





- name: 'Upload Custom Policies'
  uses: azure/powershell@v1
    inlineScript: |
      $token = Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com/"
      Install-Module -Name Microsoft.Graph.Identity.SignIns
      Select-MgProfile -Name "beta"
      Connect-MgGraph -AccessToken $token.Token
      Set-MgTrustFrameworkPolicyContent -TrustFrameworkPolicyId "B2C_1A_TrustFrameworkBase_GitHub" -InFile "./policies/TrustFrameworkBase.xml"
      Set-MgTrustFrameworkPolicyContent -TrustFrameworkPolicyId "B2C_1A_TrustFrameworkLocalization_GitHub" -InFile "./policies/TrustFrameworkLocalization.xml"
      Set-MgTrustFrameworkPolicyContent -TrustFrameworkPolicyId "B2C_1A_TrustFrameworkExtensions_GitHub" -InFile "./policies/TrustFrameworkExtensions.xml"
      Set-MgTrustFrameworkPolicyContent -TrustFrameworkPolicyId "B2C_1A_Signup_Signin_GitHub" -InFile "./policies/SignUpOrSignin.xml"
    azPSVersion: "latest"  



Note that we only use clientId and tenantId for the authentication as B2C tenants don't usually have subscriptions and we need to pass in an extra parameter for that to work.


In the upload step we also need to acquire an access token specifically to be able to connect to the Graph API. With a subsequent connection dance we can follow up by uploading the files from our repo with the Set-MgTrustFrameworkPolicyContent cmdlet.


With a bit of luck you'll get something like this in your logs:



I suffixed the policies with "GitHub" so it's easy to find them:



Testing the policy through the portal should load up something like this:



Just trust me when I say it works :smile:


And that's all there is to it really. Should be easy to adapt to a less PoC-like setup as well. The complete code can be found here:


Version history
Last update:
‎Jun 15 2022 03:48 AM
Updated by: