Migrating Users from a Local Database to Azure AD B2C for Login via SPA Application

Shehan Vanderputt
21 min readApr 11, 2024

In this article, I will discuss how to migrate your local identity provider to Azure AD B2C, including the migration of user accounts. I’ll explain the process of migrating existing user accounts, along with their passwords and profiles, from any identity provider database to Azure AD B2C.

While Microsoft offers detailed guidance for these tasks, based on my experience, organizing the steps can be a bit complex. Additionally, Microsoft provides multiple methods to accomplish this, but mapping them to our specific requirements can be challenging.

I will discuss the below areas for your reference.

  1. Creating a new Azure AD B2C tenant
  2. Difference between User Flow and Identity Experience Framework
  3. User migration
  4. Azure AD B2C: Just in time user migration v2
  5. Custom Policy Files
  6. Sign In
  7. Signup
  8. Configure Custom Policies
  9. Add Signing and Encryption keys for Identity Experience Framework Applications
  10. Register Identity Experience Framework Applications
  11. Implementing Web API Service and related Web API application in Azure AD B2C tenant
  12. Register a single-page application (SPA) in Azure Active Directory B2C
  13. Minor Changes on Custom Policy Files
  14. Running the Application

Creating a new Azure AD B2C tenant

Please follow the official Microsoft documentation below on Create an Azure Active Directory B2C tenant.

Difference between User Flow and Identity Experience Framework

In Azure AD B2C, you can define the business logic that users follow to access your application. For instance, you can determine the sequence of steps users undergo during sign-in, sign-up, profile editing, or password reset. Upon completing the sequence, the user obtains a token and gains access to your application.

Azure AD B2C offers two ways to provide identity user experiences.

  • User flows: Predefined, built-in, configurable policies that enable you to create sign-up, sign-in, and policy editing experiences quickly.
  • Custom policies: Allow you to create your own user journeys for complex identity experience scenarios not supported by user flows. Azure AD B2C uses custom policies for extensibility.

The following screenshot illustrates the user flow settings UI compared to custom policy configuration files.

User flows

To set up common identity tasks, the Azure portal offers predefined and configurable policies known as user flows.

These user flow settings allow you to control identity experience behaviors in your applications, such as:

  • Account types used for sign-in, like social accounts (e.g., Facebook) or local accounts that use an email address and password.
  • Attributes to collect from the user, such as first name, last name, postal code, or country/region of residency.
  • Multifactor authentication.
  • Customization of the User interface.
  • Claims in a token received by your application after the user completes the user flow.
  • Session management.
  • … and more

Most common identity scenarios for apps can be effectively defined and implemented using user flows. We recommend using the built-in user flows unless you have complex user journey scenarios that require the full flexibility of custom policies.

Custom policies

Custom policies are configuration files that define the behavior of your Azure AD B2C tenant’s user experience. While user flows are predefined in the Azure AD B2C portal for the most common identity tasks, custom policies can be fully edited by an identity developer to accomplish various tasks.

A custom policy is fully configurable and policy-driven. It orchestrates trust between entities in standard protocols such as OpenID Connect, OAuth, and SAML, as well as a few non-standard ones, such as REST API-based system-to-system claims exchanges. The framework creates user-friendly, white-labeled experiences.

The custom policy gives you the ability to construct user journeys with any combination of steps. For example:

  • Federate with other identity providers
  • First- and third-party multifactor authentication challenges
  • Collect any user input
  • Integrate with external systems using REST API communication

Each user journey is defined by a policy. You can build as many or as few policies as you need to enable the best user experience for your organization.

A custom policy is defined by multiple XML files that refer to each other in a hierarchical chain. The XML elements define the claims schema, claims transformations, content definitions, claims providers, technical profiles, user journey orchestration steps, and other aspects of the identity experience.

Here are some useful elements found in the policy files:

  • BuildingBlocks: Contains elements defining claims schema, transformations, client definitions, and content definitions.
  • ClaimsSchema: Defines the structure and restrictions for user claims.
  • ClaimsTransformations: Defines transformations on claims data.
  • ClientDefinitions: Defines client UI filter flags.
  • ContentDefinitions: Defines error pages and their metadata.
  • TechnicalProfiles: Used to communicate with your Azure Active Directory B2C (Azure AD B2C) tenant to create a user or read a user profile.
  • UserJourneys: Defines sequences of steps users take during certain processes.

User migration

When planning to migrate your identity provider to Azure AD B2C, you may also need to migrate user accounts. The following examples demonstrate how to migrate existing user accounts, including their passwords and profiles, from any identity provider to Azure AD B2C.

Pre migration

This flow applies when you either have clear access to a user’s credentials (user name and password) or the credentials are encrypted, but you can decrypt them. The pre-migration process involves reading the users from the old identity provider and creating new accounts in the Azure AD B2C directory. Read more about Microsoft official documentation on User Migration.

Just in time migration

Just in time migration flow fits when the user’s password is not accessible. For example: Passwords are in HASH format. Or when passwords are stored in an identity provider, which you don’t have access. Your system validates user credential by calling an identity provider web service.

Microsoft has already provided 4 samples for these types of migrations.

  • just in time migration v1 — In this sample Azure AD B2C calls a REST API that validates the credential and migrate the account with a Graph API call.
  • just in time migration v2 — In this sample Azure AD B2C calls a REST API to validate the credentials, return the user profile to B2C from an Azure Table, and B2C creates the account in the directory.
  • seamless-account-migration — Where accounts have been pre-migrated into Azure AD B2C and you want to update the password on the account on initial sign in. Azure AD B2C calls a REST API to validate the credentials for accounts marked as requiring migration (via attribute) against a legacy identity provider, returns a successful response to Azure AD B2C, and Azure AD B2C writes the password to the account in the directory.
  • B2C to B2C Migration — Migrate users from one B2C instance to another using just in time migration.

Based on my client’s requirements, I selected just in time migration v2 for my work.

Azure AD B2C: Just in time user migration v2

When you plan to migrate your identity provider to Azure AD B2C, you may also need to migrate the users account as well. This article explains how to migrate existing user accounts with their passwords and profiles, from any identity provider database to Azure AD B2C.

Just in time migration flow fits when the user’s password is not accessible. For example:

  • Passwords are in HASH format
  • Passwords are stored in an identity provider, which you don’t have access. Your system validates user credential by calling an identity provider web service

jit migration v2 repository on GitHub contains the source code of a .NET project and custom policies for user migration. The project includes sign-in and sign-up functionalities implemented using .NET 2.0. Consequently, I developed a .NET 8 Web API Application for user migration. Kindly set it up on your local machine.

Please clone this project from the following link: Identity Auth Service for User Migration (github.com)

Please refer to the README.md file for further clarification on the project.

Custom Policy Files

Under the jit migration v2 repository, you’ll find a folder named “policy” containing the custom policy files. These files need to be configured before uploading them to Azure.

  • ProfileEdit.xml
  • PasswordReset.xml
  • SignUpOrSignin.xml
  • TrustFrameworkBase.xml
  • TrustFrameworkExtensions.xml

In simpler terms, we require the following files to establish a fully customized user flow.

  • Base file — Few modifications are required to the base. Example: TrustFrameworkBase.xml
  • Extension file — This file is where most configuration changes are made. Example: TrustFrameworkExtensions.xml
  • Relying party files — Task-specific files called by your application. Examples: SignUpOrSignin.xml, ProfileEdit.xml, PasswordReset.xml

The TrustFrameworkBase.xml and TrustFrameworkExtensions.xml files handle all the background processes in the user flow.

Let's start sign in and signup processes using jit-migration-v2 repository. Before proceeding, it’s essential to have a basic understanding of custom policies. Please refer to the official documentation on Custom Policies for more information.

Sign In

  1. SelfAsserted-LocalAccountSignin-Email technical profile calls the migration REST API endpoint, REST-UserMigration-LocalAccount-SignIn technical profile, sending SigninNames and password claims, as input parameters.

2. The REST API, checks if the user exists in the legacy identity provider. In this example in-memory list.

3. If exists, REST API checks if the password provided by the user is valid (compare password or call the legacy identity provider).

  • If valid the REST API returns the user profile from the in-memory list with needToMigrate claim set to local.
  • If not valid, the REST API return an error Invalid username or password.
  • If user is not existed and IsMigrated is true for the particular user, in-memory list, in the legacy identity provider, the REST API returns empty claims (needToMigrate claim is null)

4. The SelfAsserted-LocalAccountSignin-Email technical profile checks the return needToMigrate claim.

  • If the claim is null, Azure AD B2C invokes the next validation technical profile login-NonInteractive, which validates the user credential (this user already existed in the B2C directory).
  • Otherwise, Azure AD B2C invokes the next validation technical profile AAD-MigrateUserUsingLogonEmail, which migrates the account with the information return from the migration REST API.

Signup

For the sign-up the policy needs to check whether a user with such email address exists in Azure AD and also in the in-memory list. To do so, the LocalAccountSignUpWithLogonEmail technical profile:

  1. Calls the migration REST API endpoint, REST-UserMigration-LocalAccount-SignUp technical profile, sending SigninNamesclaims.
  2. The REST API checks if the user exists in the in-memory list.
  3. If exists, return an error message A user with the specified ID already exists. Choose a different one.
  4. Otherwise, B2C continues to the next validation technical profile AAD-UserWriteUsingLogonEmail that checks if user already exists in AAD and creates the account.

Configure Custom Policies

As previously mentioned, all the required policy files are available in the jit migration GitHub repository.

user-migration/jit-migration-v2(github.com)

jit-migration-v2 includes both social sign-in options (via Facebook or Google) and local account sign-in. For this guide, we’ll focus solely on configuring custom policies for local account sign-in within the Identity Experience Framework in Azure AD B2C.

Furthermore, I am concentrating on the sign-in and sign-up processes. Consequently, in this guide, I will not address profileEdit.xml and passwordReset.xml.

Configure SignUpOrSignin.xml

Replace all occurrences of your-tenant with your Azure AD B2C domain name.

<TenantId>your-tenant.onmicrosoft.com</TenantId>

Configure TrustFrameworkBase.xml

Replace all occurrences of your-tenant with your Azure AD B2C domain name.

Configure TrustFrameworkExtension.xml

  1. Replace all occurrences of your-tenant with your Azure AD B2C domain name.
  2. Locate the technical profile named login-NonInteractive. This profile is responsible for validating user credentials if the user already exists in the B2C directory, eliminating the need for additional user interaction.
<!-- Local account Sign-In claims provider --> 
<ClaimsProvider>
<DisplayName>Local Account SignIn</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="login-NonInteractive">
<Metadata>
<!--Demo action required: Change to your ProxyIdentityExperienceFramework App Id-->
<Item Key="client_id">00000000-0000-0000-0000-000000000000</Item>
<!--Demo action required: Change to your IdentityExperienceFramework App Id-->
<Item Key="IdTokenAudience">00000000-0000-0000-0000-000000000000</Item>
</Metadata>
<InputClaims>
<!--Demo action required: Change to your ProxyIdentityExperienceFramework App Id-->
<InputClaim ClaimTypeReferenceId="client_id" DefaultValue="00000000-0000-0000-0000-000000000000" />
<!--Demo action required: Change to your IdentityExperienceFramework App Id-->
<InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="00000000-0000-0000-0000-000000000000" />
</InputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>

To set up the client IDs, IdTokenAudience, and resource IDs, we must register two applications named ProxyIdentityExperienceFramework and IdentityExperienceFramework. Additionally, we need to create signin and encryption keys for these applications.

The following steps will guide you through creating the necessary components in Azure AD B2C.

Add Signing and Encryption keys for Identity Experience Framework Applications

  1. Sign in to the Azure portal.
  2. If you have access to multiple tenants, select the Settings icon in the top menu to switch to your Azure AD B2C tenant from the Directories + subscriptions menu.
  3. In the Azure portal, search for and select Azure AD B2C.
  4. On the overview page, under Policies, select Identity Experience Framework.

Create the signing key

  1. Select Policy Keys and then select Add.
  2. For Options, choose Generate.
  3. In Name, enter TokenSigningKeyContainer. The prefix B2C_1A_ might be added automatically.
  4. For Key type, select RSA.
  5. For Key usage, select Signature.
  6. Select Create.

Create the encryption key

  1. Select Policy Keys and then select Add.
  2. For Options, choose Generate.
  3. In Name, enter TokenEncryptionKeyContainer. The prefix B2C_1A_ might be added automatically.
  4. For Key type, select RSA.
  5. For Key usage, select Encryption.
  6. Select Create.

Register Identity Experience Framework Applications

Azure AD B2C requires you to register two applications that it uses to sign up and sign in users with local accounts: IdentityExperienceFramework, a web API, and ProxyIdentityExperienceFramework, a native app with delegated permission to the IdentityExperienceFramework app. Your users can sign up with an email address or username and a password to access applications registered to your tenant, which creates a “local account.” Local accounts exist only in your Azure AD B2C tenant.

You will need to register these two applications in your Azure AD B2C tenant only once.

Register the IdentityExperienceFramework application

To register an application in your Azure AD B2C tenant, you can use the App registrations experience.

  1. Select App registrations, and then select New registration.
  2. For Name, enter IdentityExperienceFramework.
  3. Under Supported account types, select Accounts in this organizational directory only.
  4. Under Redirect URI, select Web, and then enter https://your-tenant-name.b2clogin.com/your-tenant-name.onmicrosoft.com, where your-tenant-name is your Azure AD B2C tenant domain name.
  5. Under Permissions, select the Grant admin consent to openid and offline_access permissions check box.
  6. Select Register.
  7. Record the Application (client) ID for use in a later step.

Next, expose the API by adding a scope:

  1. In the left menu, under Manage, select Expose an API.
  2. Select Add a scope, then select Save and continue to accept the default application ID URI.
  3. Enter the following values to create a scope that allows custom policy execution in your Azure AD B2C tenant:
  • Scope name: user_impersonation
  • Admin consent display name: Access IdentityExperienceFramework
  • Admin consent description: Allow the application to access IdentityExperienceFramework on behalf of the signed-in user.

4. Select Add scope

Register the ProxyIdentityExperienceFramework application

  1. Select App registrations, and then select New registration.
  2. For Name, enter ProxyIdentityExperienceFramework.
  3. Under Supported account types, select Accounts in this organizational directory only.
  4. Under Redirect URI, use the drop-down to select Public client/native (mobile & desktop).
  5. For Redirect URI, enter myapp://auth.
  6. Under Permissions, select the Grant admin consent to openid and offline_access permissions check box.
  7. Select Register.
  8. Record the Application (client) ID for use in a later step.

Next, specify that the application should be treated as a public client:

  1. In the left menu, under Manage, select Authentication.
  2. Under Advanced settings, in the Allow public client flows section, set Enable the following mobile and desktop flows to Yes.
  3. Select Save.
  4. Ensure that allowPublicClient: true is set in the application manifest:
  5. In the left menu, under Manage, select Manifest to open application manifest.
  6. Find allowPublicClient key and ensure its value is set to true.

Now, grant permissions to the API scope you exposed earlier in the IdentityExperienceFramework registration:

  1. In the left menu, under Manage, select API permissions.
  2. Under Configured permissions, select Add a permission.
  3. Select the APIs my organization uses tab, then select the IdentityExperienceFramework application.
  4. Under Permission, select the user_impersonation scope that you defined earlier.
  5. Select Add permissions. As directed, wait a few minutes before proceeding to the next step.
  6. Select Grant admin consent for <your tenant name)>.
  7. Select Yes.
  8. Select Refresh, and then verify that “Granted for …” appears under Status for the scope.

Now, you can fill in the required fields in the login-noninteractive technical profile. I’ve already provided this information in the previous section under “Configure TrustFrameworkExtension.xml”.

- MetaData
client_id = Application (client) ID for ProxyIdentityExperienceFramework
IdTokenAudience = Application (client) ID for IdentityExperienceFramework
- InputClaims
client_id = Application (client) ID for ProxyIdentityExperienceFramework
resource_id = Application (client) ID for IdentityExperienceFramework

Implementing Web API Service and related Web API application in Azure AD B2C tenant

Implementing Web API Service

I have created .NET 8 Web API Application for Web API Service. Please setup it on your local machine.

Please follow the link AzureB2C_TodoListService (github.com)

Please read README.md for further clarification on the project.

Registering an Application

The Microsoft identity platform performs identity and access management (IAM) only for registered applications. Whether it’s a client application like a web or mobile app, or it’s a web API that backs a client app, registering it establishes a trust relationship between your application and the identity provider, the Microsoft identity platform.

To register an application in your Azure AD B2C tenant, Follow the below steps.

  1. Sign in to the Azure portal.
  2. If you have access to multiple tenants, select the Settings icon in the top menu to switch to your Azure AD B2C tenant from the Directories + subscriptions menu.
  3. In the left menu, select Azure AD B2C. Or, select All services and search for and select Azure AD B2C.
  4. Select App registrations, and then select New registration.
  5. Enter a Name for the application. For example, webapi1.
  6. Under Redirect URI, select Web, and then enter an endpoint where Azure AD B2C should return any tokens that your application requests. In a production application, you might set the redirect URI an endpoint like https://localhost:5000. During development or testing, you can set it to https://jwt.ms, a Microsoft-owned web application that displays the decoded contents of a token (the contents of the token never leave your browser). You can add and modify redirect URIs in your registered applications at any time.
  7. Select Register.
  8. Record the Application (client) ID for use in your web API’s code.

Configure scopes

Scopes provide a way to govern access to protected resources. Scopes are used by the web API to implement scope-based access control. For example, users of the web API could have both read and write access, or users of the web API might have only read access.

  1. Select App registrations.
  2. Select the webapi1 application to open its Overview page.
  3. Under Manage, select Expose an API.
  4. Next to Application ID URI, select the Add link.
  5. Replace the default value (a GUID) with api, and then select Save. The full URI is shown, and should be in the format https://your-tenant-name.onmicrosoft.com/api. When your web application requests an access token for the API, it should add this URI as the prefix for each scope that you define for the API.
  6. Under Scopes defined by this API, select Add a scope.
  7. Enter the following values to create a scope that defines read access to the API, then select Add scope:
  8. Scope name: task.read
  9. Admin consent display name: Read access to task API
  10. Admin consent description: Allows read access to the task API
  11. Select Add a scope, enter the following values to add a scope that defines write access to the API, and then select Add scope:
  12. Scope name: task.write
  13. Admin consent display name: Write access to task API
  14. Admin consent description: Allows write access to the task API

Register a single-page application (SPA) in Azure Active Directory B2C

Many modern web applications are built as client-side single-page applications (“SPAs”). Developers write them by using JavaScript or an SPA framework such as Angular, Vue, and React. These applications run on a web browser and have different authentication characteristics than traditional server-side web applications.

Azure AD B2C provides two options to enable single-page applications to sign in users and get tokens to access back-end services or web APIs:

Authorization code flow (with PKCE)

OAuth 2.0 Authorization code flow (with PKCE) allows the application to exchange an authorization code for ID tokens to represent the authenticated user and Access tokens needed to call protected APIs. In addition, it returns Refresh tokens that provide long-term access to resources on behalf of users without requiring interaction with those users.

To take advantage of this flow, your application can use an authentication library that supports it, like MSAL.js.

Implicit grant flow

Some libraries, like MSAL.js 1.x, only support the implicit grant flow or your applications is implemented to use implicit flow. In these cases, Azure AD B2C supports the OAuth 2.0 implicit flow. The implicit grant flow allows the application to get ID and Access tokens. Unlike the authorization code flow, implicit grant flow doesn’t return a Refresh token.

This authentication flow doesn’t include application scenarios that use cross-platform JavaScript frameworks such as Electron and React-Native. Those scenarios require further capabilities for interaction with the native platforms.

Register the SPA application

  1. Sign in to the Azure portal.
  2. If you have access to multiple tenants, select the Settings icon in the top menu to switch to your Azure AD B2C tenant from the Directories + subscriptions menu.
  3. In the Azure portal, search for and select Azure AD B2C.
  4. Select App registrations, and then select New registration.
  5. Enter a Name for the application. For example, spaapp1.
  6. Under Supported account types, select Accounts in any identity provider or organizational directory (for authenticating users with user flows)
  7. Under Redirect URI, select Single-page application (SPA), and then enter https://jwt.ms in the URL text box.
  8. The redirect URI is the endpoint to where authorization server (Azure AD B2C, in this case) sends the user after it completes its interaction with the user. Also, the redirect URI endpoint receives the access token or authorization code upon successful authorization. In a production application, it’s typically a publicly accessible endpoint where your app is running, like https://contoso.com/auth-response. For testing purposes like this guide, you can set it to https://jwt.ms, a Microsoft-owned web application that displays the decoded contents of a token (the contents of the token never leave your browser). During app development, you might add the endpoint where your application listens locally, like http://localhost:5000. You can add and modify redirect URIs in your registered applications at any time.
  9. The following restrictions apply to redirect URIs:
  • The reply URL must begin with the scheme https, unless using localhost.
  • The reply URL is case-sensitive. Its case must match the case of the URL path of your running application. For example, if your application includes as part of its path .../abc/response-oidc, don't specify .../ABC/response-oidc in the reply URL. Because the web browser treats paths as case-sensitive, cookies associated with .../abc/response-oidc may be excluded if redirected to the case-mismatched .../ABC/response-oidc URL.

10. Under Permissions, select the Grant admin consent to openid and offline_access permissions check box.

11. Select Register.

Enable the implicit flow

If you’re using MSAL.js 1.3 or an earlier version with the implicit grant flow in your SPA app, or if you configure the https://jwt.ms/ app for testing a user flow or custom policy, you need to enable the implicit grant flow in the app registration:

  1. In the left menu, under Manage, select Authentication.
  2. Under Implicit grant and hybrid flows, select both the Access tokens (used for implicit flows) and ID tokens (used for implicit and hybrid flows) check boxes.
  3. Select Save.

If your app uses MSAL.js 2.0 or later, don’t enable implicit flow grant as MSAL.js 2.0+ supports the authorization code flow with PKCE.

Grant permissions

To call the above created protected web API from this application, you need to grant your application permissions to the SPA Application.

  1. Select App registrations, and then select the web application that should have access to the API. For example, spaapp1.
  2. Under Manage, select API permissions.
  3. Under Configured permissions, select Add a permission.
  4. Select the My APIs tab.
  5. Select the API to which the web application should be granted access. For example, webapi1.
  6. Under Permission, expand task, and then select the scopes that you defined earlier. For example, task.read and task.write.
  7. Select Add permissions.
  8. Select Grant admin consent for (your tenant name).
  9. If you’re prompted to select an account, select your currently signed-in administrator account, or sign in with an account in your Azure AD B2C tenant that’s been assigned at least the Cloud application administrator role.
  10. Select Yes.
  11. Select Refresh, and then verify that “Granted for …” appears under Status for both scopes.

Your application is registered to call the protected web API. A user authenticates with Azure AD B2C to use the application. The application obtains an authorization grant from Azure AD B2C to access the protected web API.

Minor Changes on Custom Policy Files

After completing these steps, we are now prepared to run our application. Before doing so, we need to address any minor issues.

  1. To authenticate custom policies via app registrations, we must configure CryptographicKeys. While our jit migration v2 custom policies support social account sign-ins, but our focus is on migrating users from a custom database. Therefore, we’ll comment out the CryptographicKeys tag snippets in the TrustFrameworkBase.xml file for,
  • Google-OAUTH and
  • Facebook-OAUTH technical profiles.
<CryptographicKeys>
<Key Id="client_secret" StorageReferenceId="B2C_1A_FacebookSecret" />
</CryptographicKeys>
<CryptographicKeys>
<Key Id="client_secret" StorageReferenceId="B2C_1A_GoogleSecret" />
</CryptographicKeys>

2. Then we must configure the sign-in key and encryption key (CryptographicKeys) in multiple locations within the TrustFrameworkBase.xml file. However, they are already set up by default because we created them with the same name as TokenSigningKeyContainer and TokenEncryptionKeyContainer.

You can locate them in the technical profile IDs listed below in the TrustFrameworkBase.xml file.

  • JwtIssuer
  • AAD-Common
  • SelfAsserted-Social
  • LocalAccountSignUpWithLogonEmail
  • LocalAccountDiscoveryUsingEmailAddress
  • LocalAccountWritePasswordUsingObjectId
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
<Key Id="issuer_refresh_token_key" StorageReferenceId="B2C_1A_TokenEncryptionKeyContainer" />
</CryptographicKeys>

3. Since we do not use social account logins for now, in TrustFrameworkExtensions.xml file, set client_id as 00000000–0000–0000–0000–000000000000

<!-- Facebook claims provider -->
<ClaimsProvider>
<DisplayName>Facebook</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="Facebook-OAUTH">
<Metadata>
<!--Demo action required: Change to your Facebook App Id-->
<Item Key="client_id">00000000-0000-0000-0000-000000000000</Item>
<Item Key="scope">email public_profile</Item>
<Item Key="ClaimsEndpoint">https://graph.facebook.com/me?fields=id,first_name,last_name,name,email</Item>
</Metadata>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>

3. Since we need to upload our configured XML files to the Identity Experience Framework, we need a way to access our IdentityAuthService application. One approach is to publish IdentityAuthService and set up a public URL for the Rest API technical profile URLs for login and sign up. However, this method prevents debugging of the application. A smarter approach is to use NGROK to create a public URL for your localhost. Follow this tutorial to Set up NGROK.

Now we have a public url for https://localhost:7250

Copy the public URL and paste it within <Item Key=”ServiceUrl”>.

For login → https://2a1a-112-134-241-245.ngrok-free.app/api/auth/login

For signup → https://2a1a-112-134-241-245.ngrok-free.app/api/auth/signup
<TechnicalProfile Id="REST-UserMigration-LocalAccount-SignIn">
<DisplayName>Migrate user sign-in flow</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">https://2a1a-112-134-241-245.ngrok-free.app/api/auth/login</Item>
<Item Key="AuthenticationType">None</Item>
<Item Key="SendClaimsIn">Body</Item>
<Item Key="AllowInsecureAuthInProduction">True</Item>
</Metadata>
<InputClaims>b
<InputClaim ClaimTypeReferenceId="signInName" />
<InputClaim ClaimTypeReferenceId="password" />
<InputClaim ClaimTypeReferenceId="useInputPassword" DefaultValue="false" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="needToMigrate" />
<OutputClaim ClaimTypeReferenceId="email" />
<OutputClaim ClaimTypeReferenceId="newPassword" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surName" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>

<!--Demo: Checks if user exists in the migration table. If yes, raises an error -->
<TechnicalProfile Id="REST-UserMigration-LocalAccount-SignUp">
<DisplayName>Migrate user sign-in flow</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">https://3a33-112-134-241-245.ngrok-free.app/api/auth/signup</Item>
<Item Key="AuthenticationType">None</Item>
<Item Key="SendClaimsIn">Body</Item>
<Item Key="AllowInsecureAuthInProduction">True</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInName" />
<InputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="displayName" />
<InputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="givenName" />
<InputClaim ClaimTypeReferenceId="SurName" PartnerClaimType="SurName" />
</InputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>

Running the Application

Now that everything is set up, we’re good to go. Now we need to upload our custom policies.

  1. In the Azure portal, search for and select Azure AD B2C.
  2. In the left menu, under Policies, select Identity Experience Framework.
  3. Select Upload custom policy, browse, select, and then upload the custom policy file in the following order.
  • TrustFrameworkBase.xml
  • TrustFrameworkExtensions.xml
  • SignUpOrSignin.xml

After you upload the file, Azure AD B2C adds the prefix B2C_1A.

4. Run IdentityAuthService in your local machine.

5. Here, I’ve set up NGROK for https://localhost:7250. However, the port number may vary on your local machine, so please be sure to check it.

Then click on B2C_1A_JITMIGRAION_SIGNUP_SIGNIN.

  1. Select Application spaapp1.
  2. Select reply url https://jwt.ms.
  3. Under Access Tokens select task.read and task.write scopes.
  4. Click on Run now.

You will see a login page.

5. In IdentityAuthService -> TestUserData -> UserData.cs, I’ve provided some test users. Copy an email and password from a user, then paste them into the respective fields on the login page.

new User
{
UserFirstName = "John",
UserLastName = "Doe",
UserEmailAddress = "john.doe@example.com",
UserPassword = "1qaz@WSX",
UserPhoneNumber = "1234567890",
UserAddress = "123 Main St, Anytown, USA",
IsMigrated = false
}

You will successfully log in and be redirected to https://jwt.ms, where you will see an access token.

  • sub represents the Object ID of the user.
  • nonce is a string value used to associate a Client session with an ID Token and mitigate replay attacks.
  • scp represents the scopes.
  • azp is the Authorized party, which is the party to which the ID Token was issued. Here, it's the client ID of the spaapp1.
  • aud (audience) is a claim that identifies the recipients intended for the JWT. Here, it's the client ID of the webapi1.
  • exp is the expiration time of the token.
  • iss is the principal that issued the JWT.

6. Copy the access token.

7. Run the TodoListService project on your local machine. Ensure to set up the client_id and replace your_tenant with your actual tenant name in the app.settings.json file. The client_id should be the client ID of the webapi1.

8. Open the Postman tool.

  • In Auth tab, select Bearer Token
  • Paste your access token in the text area

You will access the Web API and retrieve results.

Side Notes

  • Try accessing the API without adding the token and inspect the HTTP status code. You will receive an Unauthorized 401 error.
  • Change your scope name and check the HTTP status code again; you will receive a Forbidden 403 error.

Scopes are used to authorize the client application only. Therefore, we need to add roles to achieve a complete authorization. Additionally, we need to configure the PasswordReset.xml and ProfileEdit.xml files and implement related APIs. In the next blog post, I will delve deeper into these areas.

--

--

Shehan Vanderputt

Azure | AWS | .NET | C# | Django | Python | MongoDB | MSSQL