Previously, I showed you how to create an Azure B2C tenant step by step in a very manual process. I promised that I would also show you how to do it automatically, and this is it!
One huge pain in this process is that Microsoft decided that, for some reason, B2C tenants need to have a real user create the tenant and not a service principal. The reason behind this, as far as I can tell, is that these tenants need to have an owner user. Unfortunately, they offer no alternative for setting this owner. It would be nice if they allowed you to specify an object/user ID that could be the owner. This means that you can’t use CI/CD to deploy tenants. I tried using ARM, PowerShell, all failed with “unauthorized” unless I was using my user account.
I was about to tell you that you could run a CLI command or use the portal to create the tenant and then run the script I’m going to walk through. Until I tried to confirm that it would work one last time. No. You can’t even run the rest of the script from a service principal account. You could perhaps use a service account if you wanted. I’d be happy for anyone to point to a different way of making this work. Until then, I could only get this to work running locally.
You can find all the config files and the PowerShell script on my demo repo.
What this does
- Creates a B2C tenant if it doesn't exist.
(The rest is run against the B2C tenant)
- Creates an API Connector
- A Custom Attribute
- Creates these App Registrations
- An app for Microsoft account social logins
- Native apps (Windows, Android, etc.)
- Identity providers (if configured)
- A user flow
You’re going to need a user with enough permissions to run the script. If you plan to use social logins via the identity providers, you’ll need a key vault setup that this user can pull/push secrets to. You’ll also need to go through the config files that I’ve created. I tried to make things as generic as possible to make it easy to customize to your organization's needs. You will probably have to customize the PowerShell script too.
Let’s go through the configuration files. There’s a config file for each of the app registrations, the user flow and a general config you’ll want per environment.
The Settings section mostly how about how the tenant is created. The Storage Account property is so that you can customize your B2C user flow templates. It’s optional and if not provided, that part of the process will be ignored. The Key Vault property is for storing and retrieving your Identity Provider keys. Again, if you don’t intend to use social logins, you can ignore this.
User Attributes is an array of additional claims you want as part of your user flows. Data type is 1 for string, 2 for boolean, 5 for int. Note that the only thing you can change after the attribute is created is the description. All other fields are locked and the only way to change them, is to delete it.
The API Connector is useful if you want to call an endpoint to do any additional validation or, as in the example, to populate the additional user attributes. I hope to cover this part in more detail in another post.
Each of the Apps sections describes where to find the app-specific config file and any additional metadata like redirect URIs that will be inserted into the config file. The app config files are a trimmed down version of the manifests you can see from the portal. Unfortunately, you can’t just copy and paste the manifest directly. In the example configs, the web and native apps get the API Access permission.
Lastly, there’s the Identity Providers. This is an array of any social providers you want to include. The technical profile id is a magic string, so you’ll have to find the values. The app secret property is the name of the secret in the key vault. If you set up Google as a social provider, for instance, you’ll get an ID and app secret. You can modify the config with the app ID and then place the secret in the key vault. This way, your secrets are not stored in your source code.
New-B2CTenant is the main course function. There’s a bit of setup to make sure that the resource group and tenant exist, but after that point is yours to customize. If you don’t need all the apps that I set up, simply remove those sections.
Running the Script
To run the process, you can open a PowerShell terminal and run:
. ./1.0-create.ps1 New-B2CTenant -Environment local
The "Environment" flag will change what configuration.*.json file is picked up.
It’s really unfortunate that all this has to be done with undocumented APIs and hacks. You will probably have to set up a tenant manually and then compare the example files with what your needs are. However, the result is a repeatable B2C tenant deployment. You can set up a tenant for your development team to use and a production tenant for your production app. There’s no risk in exposing real user data or making breaking changes. You can work on customizing the user flow templates without concern for effecting live users.
If you want to see the template would produce, please see my previous post and related video. The video provides a walkthrough of the manual process.