Invoking the Azure AD B2C custom policy journey with a JWT

The use case for this was a registration flow outside of B2C that ended with a reset password request.

The user is created via the Graph API with a dummy password. At no stage is the user aware of this password. The user then needs to reset their own password and ideally a JWT would be sent to the application.

The registration flow could invoke a custom password reset web page and this web page could then call the Graph API to reset the password.

This page would need some kind of security to avoid someone discovering the URL and using it to change any password.

There is a current B2C password reset page but this page requires the user to first validate their email address. It would not be a good user experience for the user to go through the flow and right at the end be asked to do the validation.

So I wondered if we could use the current B2C password reset page but remove the validation step and pass in the email address of the user in some secure manner. Obviously, once you remove the validation step the page is wide open to be hacked.

Some investigation revealed that this could be done by putting the email into a JWT and sending that to B2C. A MIM attack wouldn’t work because if they tried to change the email address that would invalidate the signature.

So we need a custom password reset policy.

There is an example of all the code required in this sample.

The first step is to generate the JWT. This is “Program.cs” in a console application.

We provide the issuer, the audience (the redirect URI) and a secret key to be used in the signing process. The result is a signed JWT that is displayed in the cmd prompt.

Now we move to the custom policy.

We need a RelyingParty.

Notice that InputTokenFormat is “JWT ” and the key is in a B2C key container.

The JWT generation adds a claim called “email” and this is matched to the

<InputClaim ClaimTypeReferenceId=”email” /> 


The secret key has to be shared between the code that generates the token and B2C. This means that it has to be a manual key since there is no way to get the value of a generated key after it has been created.

Now we need a “User Journey”. This is called by the RelyingParty.

We can use the existing “Password Reset” template as a start to get:

This is added to the TrustFrameworkExtensions file.

We want to:

  • Display a password reset page
  • Take the user email address and convert to a user objectID
  • Use the objectID to write the new password to B2C

This a accomplished by:

  • “AAD-UserReadUsingEmailAddress”
  • “LocalAccountWritePasswordUsingObjectId”

both of which are in the user journey.

The Technical Profile for “LocalAccountWritePasswordUsingObjectId” contains:

<Item Key=”ContentDefinitionReferenceId”>api.localaccountpasswordreset</Item>

and has the following output claims:

<OutputClaim ClaimTypeReferenceId=”newPassword” Required=”true” />
<OutputClaim ClaimTypeReferenceId=”reenterPassword” Required=”true” />

The ContentDefinition for “api.localaccountpasswordreset” contains:

<ContentDefinition Id=”api.localaccountpasswordreset”>

SelfAsserted implies a user input form that contains the two password fields as per the output claims.

To kick this all off, the URL is of the form:

&client_id=some client id

&redirect_uri=some uri






&client_assertion=generated JWT from console application

Running the URL shows:

Note that B2C will validate the JWT including expiry and signature. The token is valid for twenty minutes. Invoking the URL after say 30 minutes results in:

Using the User Journey shows:

This flow could e.g. be invoked from a SPA as:

Note that this code will result in the user being signed in — exactly the same as a normal B2C “Forgotten password” flow.

All good!




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

Recommended from Medium

Five steps to perfect software

Why the golang underscore struct field exists

Check, please! Billing in Cloud Storage

A Brief Overview of Bluetooth Low Energy

In depth Guide for Manual Testing

How to transfer USDC to Cronos network?

How I Went From a Finance Major to a Software Engineer

Python: Pros And Cons Of Lambda

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Rory Braybrook

Rory Braybrook

NZ Microsoft Identity dude and MVP. Azure AD/B2C/ADFS/Auth0/identityserver. StackOverflow: Presentations:

More from Medium

Using nested JSON in a REST API call with Azure AD B2C

Image: The word “JSON”

Authenticate Azure Static Web App Users Using Azure AD B2C

File Collaboration and MS Identity Platform

Getting rid of credentials in Azure — Part 1