Creating an approval journey with Azure AD B2C
This is a question that I have been asked a few times and there are no samples that I can refer people to.
The idea is that when someone signs up, they are not automatically added to B2C but rather have to wait until someone e.g. a manager approves the application
One approach would be the following three-step journey:
Step 1 would be a user journey with a sign-up form and then an API that sends the approval manager an email. Included in the email is a magic link that contains all the user details. This link is clicked if the manager confirms the approval.
Step 2 would be when the manager clicks the link. This kicks off a second user journey that reads the user details from the JWT in the magic link and then writes the user details to B2C. Then it sends the user an email with a magic link that contains the user’s email.
Step 3 is when the user clicks the email, it kicks off a user journey that shows them a reset password screen so they can pick their password.
The user whose email is in the magic link is the one that has the password changed.
From a security view, this is vastly superior to the user entering their password in step 1. That would mean that the manager knows the password and the password is potentially exposed in an email.
I posted about the magic link here using an id_token_hint.
The idea of a magic link is that there is a link in the email. The example below comes from the sample and “Confirm Account” is an example of the link.
In our case, the email would be something like:
The following has requested access to B2C.
Name: Joe Bloggs
Other details …
Reason for access: New employee in HR
and there would be a link saying “Approve access”.
The link would be a hyperlink to a URL like:
https://your tenant.b2clogin.com/your tenant.onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1A_MagicLink&client_id=xyz&redirect_uri=https://jwt.ms&nonce=abc&scope=openid&response_type=id_token&id_token_hint=eyJh…BKA
The JWT would look like:
"displayName": "Joe Bloggs",
"extension_Reason": "New employee in HR",
"iss": "your tenant.onmicrosoft.com",
i.e. these are the details supplied by the user during sign-up.
This is generated by the API. The API builds up the URL, constructs the JWT and signs it with a certificate as per the post above.
B2C checks the signature by getting the public key from the well-known endpoint as described here.
This is just a standard sign-up policy that asks the user to enter the details and then builds up the email to the manager that includes the magic link.
When the manager clicks on the link (i.e. approves the user creation), it invokes a custom policy.
As usual, this policy is in a gist. The policy:
- Uses “IdTokenHint_Asymmetric_ExtractClaims” to get the user details
- Writes the user details to B2C using “AAD-UserWriteUsingLogonEmail”
- Calls an API to kick off a reset password flow
Note that multiple claims can be passed in the magic link.
The policy creates the user in B2C
The reason the display name is “unknown” is because that is the default behaviour of “AAD-UserWriteUsingLogonEmail”.
The last part of step 2 calls another API that sends an email with a magic link. This link has a JWT that just contains an email address.
It invokes a custom policy that:
- Uses “IdTokenHint_Asymmetric_ExtractClaims” to get the email address
- Calls “AAD-UserReadUsingEmailAddress” to get the user’s objectID
- Calls “LocalAccountWritePasswordUsingObjectId” to invoke the password reset flow
The fact that the email address is in the JWT is why the JWT is signed. If a third party intercepted the email and tried to add a different email address to the JWT, B2C will reject it because the signature is wrong.
You can also refer to the invitation/magic link samples e.g. this.