Creating Azure AD B2C Service Principals with PowerShell

Published on
Reading time
Authors

I've been lucky enough over the last few months to be working on some cool consumer-facing solutions with one of my customers. A big part of the work we've been doing in building Minimum Viable Product (MVP) solutions to allow us to quickly test concepts in-market using stable, production ready technologies.

As these are consumer solutions, the Azure Active Directory (AAD) B2C service was an obvious choice for identity management, made even more so by AAD B2C's ability to act as a source-of-truth for consumer identity and profile information across a portfolio of applications and services.

AAD B2C and Graph API

The AAD B2C schema is extensible which allows you to add custom attributes to an identity. Some of these extension attributes you may wish the user to manage themselves (i.e. mobile phone number), and some may be system-managed or remotely-sourced value associated with the identity (i.e. Salesforce ContactID) that a user may never see or edit.

When we have attributes that the user doesn't necessarily manage themselves, or we wish to do some other processing that isn't part of the AAD B2C Policy framework we need to use the Graph API to programmatically access AAD B2C identities.

The AAD B2C team has a good overview document on how use Graph API with AAD B2C, but I ran into an issue creating a Service Principal for my Graph API code because I used an Azure AD (Enterprise) identity to create and manage my B2C instance. As I suspect this will be how the majority of instances are created I thought I would document my solution here.

Background

I have a demo AAD B2C setup below and you can clearly see my Kloud identity (creator / admin of the tenant) is sourced from "Microsoft Azure AD (other directory)".

Admin user from another directory

Note that with this user I am still able to manage identities contained in the B2C directory via the web UI, but where I run into issues is with PowerShell as we will see.

As you can see in the AAD B2C post referenced earlier, I need to use the Azure AD PowerShell module to setup a Service Principal. Firstly, let's connect:

Connect-MsolService

At the prompt I enter my admin credentials (simon.waight@kloud.com.au) and am connected.

You can probably already spot the issue... there is no way to pass a TenantId to this command - the context is entirely based on the user's User Principal Name (UPN).

When I run:

Get-MSolDomain

all I see is the verified domains attached to my home tenant:

Home tenant domains

.. and my B2C domain isn't one... so... no luck :(

I read on through the documentation and looked at the PowerShell Cmdlets and found what I thought would be my solution - the ability to specify a Tenant ID on the New-MsolServicePrincipal Cmdlet as shown:

New-MsolServicePrincipal -DisplayName "Demo AAD B2C Graph Client" `
                         -TenantId bc1ec9c8-xxxx-xxxx-xxxx-e10e3ee114a8 `
                         -Type Password `
                         -Value "notmypassword"

I promptly received an error message advising me that I was not authorised to make changes in the specified tenant :)

The Solution

It's actually pretty straight-forward - create a local adminstrative account in the AAD B2C directory and use this to authenticate when using PowerShell.

Add user step 1

Add user step 2

AAD B2C with extra admin

Once you have done this make sure to log into the Azure Portal using this new user (localadmin@simondemob2c.onmicrosoft.com in my example) and reset their password. If you are using the new AAD PowerShell Module that supports modern authentication you can do this in-line at login time.

Note: in order for MFA to work for this user at the PowerShell command prompt you should install the preview AAD module that supports modern authentication.

If I now run

Get-MSolDomain

I see the B2C directory I expect:

B2C tenant domains

I am now able to create the Service Principal I need for my Graph API client too:

New-MsolServicePrincipal -DisplayName "Demo AAD B2C Graph Client" `
                         -Type Password `
                         -Value "notmypassword"

returns the expected result of creating a Service Principal I can use for my Graph client.

Happy Days!