El Mac
El Mac

Reputation: 3419

AAD B2C: Search Users by PrincipalName

I have followed the documentation to find a registered User by Sign In Name.

The sample shows the following code to return any user with a Sign In Name [email protected]:

var users = await graphClient.Users
    .Request()
    .Filter("identities/any(c:c/issuerAssignedId eq '[email protected]' and c/issuer eq 'contoso.onmicrosoft.com')")
    .GetAsync();

Now I am trying to implement a search, which should search users without entering the full signInName. Since the filter appears to be OData, I tried to enhance it using the contains method:

var users = await graphClient.Users
    .Request()
    .Filter($"identities/any(c:contains(c/issuerAssignedId,'j.smith') and c/issuer eq 'contoso.onmicrosoft.com') ")
    .Top(5)
    .GetAsync();

Now I receive the following error when I run this new query:

Status Code: BadRequest
Microsoft.Graph.ServiceException: Code: Request_BadRequest
Message: An unknown function with name 'contains' was found. This may also be a key lookup on a navigation property, which is not allowed.

Do I have a typo somewhere or is contains not allowed? I don't think the issuerAssignedId is a lookup or a navigation property. Since I'm working with Azure AD B2C, the $search function is also not working according to the same documentation page, so I am now stuck.

What is the way to search users in Azure AD B2C?

Edit

I have found two more StackOverflow articles talking about this, but they are quite old. In one of them, a Microsoft employee points out that one could use the startswith operator.

I have tried implementing it like this, but it also throws an error.

.Filter($"identities/any(a:startswith(a/issuerAssignedId,'{username}') and a/issuer eq '{issuer}') ")
Status Code: BadRequest
Microsoft.Graph.ServiceException: Code: Request_BadRequest
Message: Unsupported property or property value or combination of property and operation occured

More sources:

Upvotes: 1

Views: 1047

Answers (2)

Marc Hägele
Marc Hägele

Reputation: 342

I use the following code to get the User by a username or login email to query the Azure AD B2C.

  string usernameOrEmail = "[email protected]";
  string aadB2CIssuerDomain = "yourtenant.onmicrosoft.com";

  public async Task<User[]> GetGraphApiUsersByUsernameEmail(string usernameOrEmail)
  {
    var users = await _graphServiceClient
    .Users
    .GetAsync(requestConfiguration =>
    {
      requestConfiguration.QueryParameters.Filter = $"identities/any(c:c/issuerAssignedId eq '{usernameOrEmail}' and c/issuer eq '{aadB2CIssuerDomain}')";
    });

     

    foreach (var user in users.Value.ToList().Select(e => new
    {
      e.DisplayName,
      e.Id,
      e.Identities,
      e.Mail,
      e.UserPrincipalName,

    }))
    {
      Console.WriteLine(JsonConvert.SerializeObject(user));
    }

    return users?.Value.ToArray();
  }

Hope it helps. Kind regards

Upvotes: 1

astaykov
astaykov

Reputation: 30903

With the note that contains operator is currently not supported on any MS Graph queries, there is a workaround with startsWith.

The Microsoft Graph implementation for lookup the identities property is limited to providing exact values for both issuerAssignedId and issuer.

A workaround that I have implemented is to keep the issuerAssignedId in additional extension attribute. This is relatively easy to implement if you use custom policies. But if you use user flows, it will be error prone as there is no direct way to record this value as additional attribute. You have to, basically, constantly query MS Graph for (delta at best!) users and update custom attribute based on issuerAssignedId.

Upvotes: 1

Related Questions