How do I create a user with custom properties in AAD B2C using the graph api

Viewed 1998

In my B2C Tenant I have 4 custom user attributes defined. Using the CLI app defined here:https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-devquickstarts-graph-dotnet#create-consumer-user-accounts When I add my custom properties to the .json for user creation, such as

{
  "accountEnabled": true,
  "signInNames": [
    {
      "type": "emailAddress",
      "value": "mail@example.com"
    }
  ],
  "creationType": "LocalAccount",
  "displayName": "Joe Consumer",
  "passwordProfile": {
    "password": "P@ssword!",
    "forceChangePasswordNextLogin": false
  },
  "passwordPolicies": "DisablePasswordExpiration",
  "canViewSoccer": true
}

I get the error:

Error Calling the Graph API:
{
  "odata.error": {
    "code": "Request_BadRequest",
    "message": {
      "lang": "en",
      "value": "One or more property values specified are invalid."
    },
    "date": "2019-01-09T16:07:16",
    "requestId": "a1e30ffb-c675-4def-9741-d2a6aceb96c7",
    "values": null
  }
}

What do I need to do to be able to use my custom properties in user creation

3 Answers

A custom attribute must be formatted as:

"extension_{app_id}_{property_name}": "{property_value}"

Example:

"extension_917ef9adff534c858b0a683b6e6ec0f3_CanViewSoccer": true

where {app_id} must be set to the application ID of the b2c-extensions-app application that is registered in your Azure AD B2C tenant.

The application id of the from b2c-extensions-app must be used without the hyphens in the extension property name. I.e.

{ "extension_e716a572-5e58-4d44-a366-ae39913b50f8_canViewSoccer": true }

should be

{ "extension_e716a5725e584d44a366ae39913b50f8_canViewSoccer": true }

See this example, UserService.CreateUserWithCustomAttribute(): https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/4-WebApp-your-API/4-2-B2C

public static async Task CreateUserWithCustomAttribute(GraphServiceClient graphClient, string b2cExtensionAppClientId, string tenantId)
{
    if (string.IsNullOrWhiteSpace(b2cExtensionAppClientId))
    {
        throw new ArgumentException("B2C Extension App ClientId (ApplicationId) is missing in the appsettings.json. Get it from the App Registrations blade in the Azure portal. The app registration has the name 'b2c-extensions-app. Do not modify. Used by AADB2C for storing user data.'.", nameof(b2cExtensionAppClientId));
    }

    // Declare the names of the custom attributes
    const string customAttributeName1 = "FavouriteSeason";
    const string customAttributeName2 = "LovesPets";

    // Get the complete name of the custom attribute (Azure AD extension)
    Helpers.B2cCustomAttributeHelper helper = new Helpers.B2cCustomAttributeHelper(b2cExtensionAppClientId);
    string favouriteSeasonAttributeName = helper.GetCompleteAttributeName(customAttributeName1);
    string lovesPetsAttributeName = helper.GetCompleteAttributeName(customAttributeName2);

    Console.WriteLine($"Create a user with the custom attributes '{customAttributeName1}' (string) and '{customAttributeName2}' (boolean)");

    // Fill custom attributes
    IDictionary<string, object> extensionInstance = new Dictionary<string, object>();
    extensionInstance.Add(favouriteSeasonAttributeName, "summer");
    extensionInstance.Add(lovesPetsAttributeName, true);

    try
    {
        // Create user
        var result = await graphClient.Users
        .Request()
        .AddAsync(new User
        {
            GivenName = "Casey",
            Surname = "Jensen",
            DisplayName = "Casey Jensen",
            Identities = new List<ObjectIdentity>
            {
                new ObjectIdentity()
                {
                    SignInType = "emailAddress",
                    Issuer = tenantId,
                    IssuerAssignedId = "casey.jensen@example.com"
                }
            },
            PasswordProfile = new PasswordProfile()
            {
                Password = Helpers.PasswordHelper.GenerateNewPassword(4, 8, 4)
            },
            PasswordPolicies = "DisablePasswordExpiration",
            AdditionalData = extensionInstance
        });

        string userId = result.Id;

        Console.WriteLine($"Created the new user. Now get the created user with object ID '{userId}'...");

        // Get created user by object ID
        result = await graphClient.Users[userId]
            .Request()
            .Select($"id,givenName,surName,displayName,identities,{favouriteSeasonAttributeName},{lovesPetsAttributeName}")
            .GetAsync();

        if (result != null)
        {
            Console.ForegroundColor = ConsoleColor.Blue;
            Console.WriteLine($"DisplayName: {result.DisplayName}");
            Console.WriteLine($"{customAttributeName1}: {result.AdditionalData[favouriteSeasonAttributeName].ToString()}");
            Console.WriteLine($"{customAttributeName2}: {result.AdditionalData[lovesPetsAttributeName].ToString()}");
            Console.WriteLine();
            Console.ResetColor();
            Console.WriteLine(JsonConvert.SerializeObject(result, Formatting.Indented));
        }
    }
    catch (ServiceException ex) 
    {
        if (ex.StatusCode == System.Net.HttpStatusCode.BadRequest)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine($"Have you created the custom attributes '{customAttributeName1}' (string) and '{customAttributeName2}' (boolean) in your tenant?");
            Console.WriteLine();
            Console.WriteLine(ex.Message);
            Console.ResetColor();
        }                
    }
    catch (Exception ex)
    {
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine(ex.Message);
        Console.ResetColor();
    }
}

If you want you can avoid using the helpers at the top. The string key in the extensionInstance dictionary will be "extension_{app id}_{property name}" where the {app id} is the id of the default app created for you with the name b2c-extensions-app. Do not modify. Used by AADB2C for storing user data.

Related