Rory Braybrook
Dec 17, 2018 · 4 min read

Adding JavaScript (JS) to the B2C UI customisation flow has been on the cards for a while and now has finally been released.

I suggest you read through all the links below and then read through the post.

There’s a good write-up here.

Let’s follow the article.

Page contract

This is described here.

Find the <ContentDefinitions> section in your TrustFrameworkExtensions custom policy.

You then need to replace all the contracts e.g.

<ContentDefinition Id=”api.error”>
<! — <DataUri>urn:com:microsoft:aad:b2c:elements:globalexception:1.1.0</DataUri> →
<Item Key=”DisplayName”>Error page</Item>

Find the old DataUri in the table in the page contracts link and replace it with the new one e.g. for “api.error” the table entry is:

urn:com:microsoft:aad:b2c:elements:globalexception:1.1.0 urn:com:microsoft:aad:b2c:elements:contract:globalexception:1.1.0

Add ScriptExecution element

As per the JS link, this is just adding:


to e.g. SignUpOrSignin.xml.

Upload the JS

The article says:

“ Include this code snippet into your sign-up or sign-in template for a self-asserted page”.

This is somewhat vague. You need to follow the steps here. There’s a lot of them but just work through them one by one.

In terms of “Create your HTML5 content”, I used the “Password toggle” sample. My HTML is:

<!DOCTYPE html>
<div id="api"></div>
function makePwdToggler(pwd){
// Create show-password checkbox
var checkbox = document.createElement('input');
checkbox.setAttribute('type', 'checkbox');
var id = + 'toggler';
checkbox.setAttribute('id', id);
var label = document.createElement('label');
label.setAttribute('for', id);
label.appendChild(document.createTextNode('show password'));
var div = document.createElement('div');
// Add show-password checkbox under password input
pwd.insertAdjacentElement('afterend', div);
// Add toggle password callback
function toggle(){
if(pwd.type === 'password'){
pwd.type = 'text';
} else {
pwd.type = 'password';
checkbox.onclick = toggle;
// For non-mouse usage
checkbox.onkeydown = toggle;
function setupPwdTogglers(){
var pwdInputs = document.querySelectorAll('input[type=password]');
for (var i = 0; i < pwdInputs.length; i++) {

Note the:

<div id="api"></div>

This is where Azure AD B2C adds the actual login page elements.

After working through the steps and assuming you used blob storage (as opposed to a web site) you should end up with the HTML uploaded to:

and your “Content Definition” pointing to this.

<ContentDefinition Id="api.signuporsignin">

Remember to upload your changed custom policies:

  • SignUpOrSignin.xml
  • TrustFrameworkExtensions.xml


Configuring the CORS “Allowed origins” field using:

resulted in the error:

‘AADB2C90047: The resource ‘$root/customize-ui.html' contains script errors preventing it from being loaded.

I was able to get around this by entering “*” i.e. allow all.

Running my “sign-up or sign-in” custom policy shows:


Instead of uploading to blob storage manually, you can use the utility.

As per the documentation:

“A simple program that uploads a directory of files to an Azure Blob Storage Account and enables CORS access for the files. Used for uploading HTML, CSS, and image files for B2C UI customization.

To run, simply download, unzip it, and run B2CAzureStorageClient.exe.”

Note that the utility uploads the contents of a directory.

When you run it, you’ll see:

**************** Azure AD B2C Blob Storage Helper Tool
This tool will upload all contents of a directory to an Azure Blob Storage Container you specify.
It will also enable CORS access from all origins on each of the files.

Enter your Azure Storage Account name:
Enter your Azure Blob Storage Primary Access Key:
Enter your Azure Blob Storage Container name:
Enter the path to the directory whose contents you wish to upload:
Sucessfully uploaded file customize-ui.html to Azure Blob Storage
Successfully set CORS policy, allowing GET on all origins. See
https://msdn.mic for more.
Press Enter to close…

You can get the Azure Blob Storage Primary Access Key from the blob storage menu:

Looking at the CORS policy section under blob storage after running the utility, we see:

All good!

The new control plane

“Identity is the new control plane”. Articles around Microsoft Identity, Auth0 and identityserver. Click the “Archive” link at the bottom for more posts.

Rory Braybrook

Written by

NZ Microsoft Identity dude. Microsoft MVP. Azure AD/B2C/ADFS. Plus Auth0/identityserver. N. Shore .NET UG Admin. Presentations:

The new control plane

“Identity is the new control plane”. Articles around Microsoft Identity, Auth0 and identityserver. Click the “Archive” link at the bottom for more posts.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade