How to view all Azure AD B2C users programmatically

This post shows how to get a list of Azure AD B2C users programmatically by using the Graph API client for .Net in a .Net Core (8) MVC web app.

I've built an entire Azure AD B2C User Management solution that is available for free on Github. The code samples below are part of this larger solution. Feel free to use this application as you see fit. Contact me if you run into any issues or need help consulting on your Azure AD B2C project.

Prerequisites

You will need the following to get started:

  1. Azure AD B2C Tenant: You need an Azure AD B2C tenant set up.
  2. App Registration: Register an application in your B2C tenant and configure API permissions.
  3. Client Credentials: Note down your client ID, client secret, and tenant ID.

Setting Up the B2CUsersService

I've created a service class called B2CUsersService that handles the interaction with Microsoft Graph API. We'll use the ClientSecretCredential from the Azure.Identity library to authenticate.

The B2CUsersService constructor utilizes the appsettings.json file to get the tenantId, clientId and clientSecret values. Open the appsettings.json file from the root of the web project. There you will enter the client id, client secret and tenant id for your B2C tenant.

Step 1: Initialize the Graph Service Client

Create the B2CUsersService and initialize the GraphServiceClient in the constructor using the client credentials flow. Make sure to request the /.default scope, which includes all the permissions granted to the app in the Azure portal.

using Azure.Identity;
using Microsoft.Graph;
using Microsoft.Graph.Models;
using System.Reflection;
namespace B2CUserAdmin.Web.Services;

public class B2CUsersService
{
private readonly GraphServiceClient \_graphServiceClient;
private readonly IConfiguration \_configuration;

    public B2CUsersService(IConfiguration configuration)
    {
        // The client credentials flow requires that you request the
        // /.default scope, and pre-configure your permissions on the
        // app registration in Azure. An administrator must grant consent
        // to those permissions beforehand.
        var scopes = new[] { "https://graph.microsoft.com/.default" };

        // using Azure.Identity;
        var options = new ClientSecretCredentialOptions
        {
            AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
        };

        var tenantId = _configuration["AzureAdB2C:TenantId"];
        var clientId = _configuration["AzureAdB2C:ClientId"];
        var clientSecret = _configuration["AzureAdB2C:ClientSecret"];

        // https://learn.microsoft.com/dotnet/api/azure.identity.clientsecretcredential
        var clientSecretCredential = new ClientSecretCredential(
            tenantId, clientId, clientSecret, options);

        _graphServiceClient = new GraphServiceClient(clientSecretCredential, scopes);

    }

    //More methods

}

Step 2: Retrieve the List of Users

Next, create a method to fetch users from Azure AD B2C. This method uses the GraphServiceClient to send a request to Microsoft Graph and retrieve the users. Use the .Select method to identify what fields to return that might fall outside of the basic list of user properties to return. Do not pass QueryParameters if you are OK with returning the default properties of the user object.

public async Task<IEnumerable<User>> GetUsersAsync()
{
var users = await \_graphServiceClient.Users
.GetAsync(requestConfiguration =>
{
requestConfiguration.QueryParameters.Select = ["displayName", "id", "identities", "otherMails"];

            });

        return users.Value;
    }

Full Implementation

Here's the complete implementation of the B2CUsersService:

using Azure.Identity;

using Microsoft.Graph;
using Microsoft.Graph.Models;
using System.Reflection;
namespace B2CUserAdmin.Web.Services;

public class B2CUsersService
{
private readonly GraphServiceClient \_graphServiceClient;
private readonly IConfiguration \_configuration;

    public B2CUsersService(IConfiguration configuration)
    {
        // The client credentials flow requires that you request the
        // /.default scope, and pre-configure your permissions on the
        // app registration in Azure. An administrator must grant consent
        // to those permissions beforehand.
        var scopes = new[] { "https://graph.microsoft.com/.default" };

        // using Azure.Identity;
        var options = new ClientSecretCredentialOptions
        {
            AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
        };

        var tenantId = _configuration["AzureAdB2C:TenantId"];
        var clientId = _configuration["AzureAdB2C:ClientId"];
        var clientSecret = _configuration["AzureAdB2C:ClientSecret"];

        // https://learn.microsoft.com/dotnet/api/azure.identity.clientsecretcredential
        var clientSecretCredential = new ClientSecretCredential(
            tenantId, clientId, clientSecret, options);

        _graphServiceClient = new GraphServiceClient(clientSecretCredential, scopes);

    }

    public async Task<IEnumerable<User>> GetUsersAsync()
    {
        var users = await _graphServiceClient.Users
            .GetAsync(requestConfiguration =>
            {
                requestConfiguration.QueryParameters.Select = ["displayName", "id", "identities", "otherMails"];

            });

        return users.Value;
    }

Display the list of users

This example is using .Net 8 and the MVC pattern. The service code above will work in other implementations than MVC. This is how to view the list of users in a simple MVC Razor view.

Index.cshtml

@model IEnumerable<Microsoft.Graph.Models.User>

@{
ViewData["Title"] = "User List";
}

<h2>@ViewData["Title"]</h2>

<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Identity/User Name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var user in Model)
{
<tr>
<td>@user.DisplayName</td>
<td>
@{
var displayIdentities = user.Identities?
.Where(identity => identity.SignInType != "userPrincipalName")
.Select(identity => $"{identity.SignInType}: {identity.IssuerAssignedId} ({identity.Issuer})");

    var displayOtherMails = user.OtherMails;

}

@if (displayIdentities != null && displayIdentities.Any())
{
<p>Identities: @string.Join(", ", displayIdentities)</p>
}

@if (displayOtherMails != null && displayOtherMails.Any())
{
<p>Other Emails: @string.Join(", ", displayOtherMails)</p>
}
</td>
<td><a asp-action="Details" asp-route-id="@user.Id">View</a> | <a asp-action="Edit" asp-route-id="@user.Id">Edit</a></td>
</tr>
}
</tbody>
</table>

UsersController.cs

using Microsoft.AspNetCore.Mvc;
using B2CUserAdmin.Web.Services;
using B2CUserAdmin.Models;
namespace B2CUserAdmin.Web.Controllers;

public class UsersController : Controller
{
private B2CUsersService \_graphAPIService;
private readonly IConfiguration \_configuration;
private readonly ILogger<UsersController> \_logger;

    public UsersController(IConfiguration configuration,
    ILogger<UsersController> logger, B2CUsersService graphAPIService)
    {
        _configuration = configuration;
        _logger = logger;
        _graphAPIService = graphAPIService;
    }

    public async Task<IActionResult> Index()
    {
        var users = await _graphAPIService.GetUsersAsync();
        return View(users);
    }

}

Running the Code

To run this code, make sure you've added the necessary NuGet packages:

  • Microsoft.Graph
  • Azure.Identity

You can install these packages using the following commands:

dotnet add package Microsoft.Graph
dotnet add package Azure.Identity

Now run dotnet run and navigate to /users where you should see a list of your Azure AD B2C users for the tenant you created the credential for.

A list of Azure AD B2C Users

Conclusion

With this setup, you can now retrieve a list of users from your Azure AD B2C tenant programmatically. This approach is scalable and can be integrated into various applications to manage your B2C users efficiently. If you encounter any issues or have questions, feel free to reach out. Happy coding!