Skip to content

Developing an AAD B2C app with MSAL Python

Ray Luo edited this page Nov 8, 2019 · 8 revisions

Use MSAL Python to work with B2C

Summary

You can use MSAL Python to sign-in users with social identities, acquire token, customize the sign-in experience, by using Azure AD B2C. AAD B2C is built around the notion of User Flows (formerly known as policies). In MSAL Python, specifying a user flow translates to providing an authority.

  • When you instantiate the client application, you need to specify the user flow in authority as https://{tenant_name}.b2clogin.com/{tenant_name}.onmicrosoft.com/{user_flow}. And then every usual acquire_token_by_xyz(...) would work with that user flow. There is no API surface difference between B2C and non-B2C scenarios. Just swap a different set of configuration, and the same web app sample would work for both non-B2C and B2C scenarios.
  • Some user flows, such as Edit Profile user flow or Reset Password user flow, are essentially customized user experience. You can get a URL to those pages by creating a PublicClientApplication with the authority containing that {user_flow}, and then calling the get_authorization_request_url(...). (In our web app sample, we even provide a higher level helper for them.)

More details of these summary are described below.

Authority for a B2C tenant and user flow

The authority to use is https://{tenant_name}.b2clogin.com/{tenant_name}.onmicrosoft.com/{user_flow} where:

  • tenant_name is the name of the Azure AD B2C tenant, such as "contoso"
  • user_flow is the name of the user flow to apply (for instance you might have "b2c_1_susi" for sign-in/sign-up).

When building the application, you need to provide, as usual, the authority, built as above

app = msal.PublicClientApplication(  # Or ConfidentialClientApplication(...)
    "your_client_id",
    authority="https://contoso.b2clogin.com/contoso.onmicrosoft.com/b2c_1_susi",
    ...)

You may also use your own customized domain name, so that your authority would look like "https://contoso.com/{tenant_name}.onmicrosoft.com/{user_flow}".

Under the hood, MSAL Python will automatically adjust the validate_authority check behavior for all B2C domains. So that you do not have to do anything extra.

Acquiring a token

Acquiring a token for an Azure AD B2C protected API, based on the user flow already provided as part of the authority, are exactly the same as what you would do in non-B2C scenario. That's why our non-B2C Python web app sample doubles as a B2C web app sample. Its major file app.py works on both non-B2C and B2C scenarios without any change.

app.acquire_token_by_xyz(...)  # Same as in non-B2C scenarios

There is no need to filter accounts by user flow, as long as you are following a pattern of "create different msal app for different user flow" (because the B2C user flow is designed to behave like an isolated authority). In practice, you will still typically reuse same MSAL app and its token cache for the SignIn user flow, and only create new one-time MSAL app when invoking EditProfile or ResetPassword user flows, whose returned token (if any) would not be useful anyway.

Example of EditProfile and ResetPassword user flows

EditProfile and ResetPassword user flows are:

  • less about acquiring tokens. That might not be obvious, but it is because currently the tokens issued by one B2C user flow are not necessarily compatible with tokens issued by another B2C user flow. Nonetheless, the safer pattern is to organize your web app to not share those tokens.
  • more about a customized user experience. Imagine in an old school web app (even outside of the context of MSAL or B2C), how would you provide a customized Edit Profile experience? You would include a link into your web app's navigation bar, pointing to that customized page.

Our B2C web app sample is exactly organized that way to hide all the underlying decisions. You would just need to update your HTML template to include new link to, for example, the Edit Profile page.

<a href='{{_build_auth_url(authority=config["B2C_PROFILE_AUTHORITY"])}}'>Edit Profile</a>

Resource Owner Password Credentials (ROPC) With B2C

There is still no API difference here between B2C and non-B2C scenario. The following content serves as a mini-tutorial.

  • In your AzureAD B2C tenant, create a new user flow and select Sign in using ROPC. This will enable the ROPC user flow for your tenant. See Configure the resource owner password credentials flow for more details.
  • Once you create the msal instance with the authority which contains the ROPC user flow, the acquire_token_by_username_password(...) would work as usual.
  • Limitations: This only works for local accounts (where you register with B2C using an email or username). This flow does not work if federating to any of the IdPs supported by B2C (Facebook, Google, etc...).
  • Normal caveats on ROPC flow still applies. Please see this wiki page.

Caching with B2C in MSAL Python

Known issue with Azure B2C:

MSAL Python token cache usage pattern starts with querying all existing accounts by get_accounts(...), which supports a username parameter as filter. That username data is populated by a preferred_username claim inside the ID Token.

By default, that claim is missing in many of the Azure AD B2C scenarios.

The customer impact is that when trying to display the accounts, their username field would be empty. This may not bother you, if you are using Auth Code flow in your web app, and dealing with only one account per user. But if you are using ROPC flow and feels you already know the end user's username, accounts = app.get_accounts(username="[email protected]") would still give you an empty result, because "[email protected]" won't match "".

The workaround is to customize your B2C user flow to populate and return a preferred_username claim, or simply call your app.get_accounts() without a specific username parameter.

Samples illustrating acquiring tokens interactively with MSAL Python for B2C applications

Sample Platform Description
Microsoft Identity Python Web App All platforms supporting Python A web app showcasing how to use MSAL Python to authenticate users via Azure Active Directory B2C, and access a Web API with the resulting tokens.