Create an Entra Local User Account via Microsoft Graph with .NET

Create an Entra Local User Account via Microsoft Graph with .NET

Create an Entra Local User Account via Microsoft Graph with .NET

The Microsoft Graph and Entra documentation are both very comprehensive and provide a lot of information - but they often contain no examples or no working examples. In addition, the SDKs are either not, insufficiently or incorrectly documented.

In this article, I will show you how to create a local user in Entra External Identities with Microsoft Graph - and this example even works!

Requirements

Necessary information

  • You need your tenant domain (either mydomain.onmicrosoft.com or a custom domain like mydomain.com)

Basically, using an Entra Local account means that you are primarily responsible for the administration. And although the documentation tells you that certain values are set automatically, you have to do this yourself. The SDK is simply incorrectly documented here - as is unfortunately so often the case.

Creation of the user principal name

The User Principal Name (UPN) is the unique identification of a user in your tenant. It basically consists of the user name and the domain. With an external user, however, you do not have a user name and have to think of something yourself. The domain is mandatory and must correspond to the domain of your tenant (e.g. mydomain.onmicrosoft.com). Something the SDK could have done for you, but good SDKs are unfortunately in short supply. For the user name, I make it easy for myself and use a prefix together with the UserId that the user has(will have in the database in my system.

The format therefore corresponds to user_<userid>@<domain>
At the end it looks like user_25e54711-a403-4290-a47e-d228ff7beb28@mydomain.onmicrosoft.com

This allows me to link the entry in Entra with the entry in the database at any time (for example to cleanup corrupt entries). The user itself is later linked to the Entra Object Id in the database, as recommended by Microsoft.

Creating a user

The actual creation of the user is simple if you know what you need. Even if the SDK tells you that property XYZ has to be set, but property X does not - absolute nonsense. You are bombarded with useless error messages.

What works is the following minimal setup:

// inputs
Guid userId = ...
string emailAddress = ...
string password = ...

// create new user object
string newUpn = $"user_{userId}@{options.TenantDomain}";

User newUser = new()
{
    AccountEnabled = false, // enable this, if you want
    DisplayName = emailAddress,

    PasswordPolicies = "DisablePasswordExpiration,DisableStrongPassword", // remove this, if you want
    PasswordProfile = new PasswordProfile
    {
        ForceChangePasswordNextSignIn = false,
        Password = password
    },

    // Local User - all properties are required
    CreationType = "LocalAccount",
    UserType = "Member",
    UserPrincipalName = newUpn,
    Identities =
    [
        new() {
            SignInType = "emailAddress",
            Issuer = _clientContext.Domain,
            IssuerAssignedId = emailAddress
        }
    ]
};

This setup...

  • ... creates a local user with a password
  • ... the password policies for expiration and password rules are disabled (we don't want expiration, and we have slightly customized rules for Entra - but you can just leave both enabled if you want)
  • ... the account is initially deactivated (as the user must first validate their e-mail address, after which the account is activated)
  • ... the user name is generated from the e-mail address
  • ... the user is created as LocalAccount, which is a fixed value - as is the UserType Member,
  • ... the login takes place via the e-mail address, which we pass as emailAddress.
  • ... the Issuer is the domain of your tenant

Actually, creating a local user in Entra External Identities is not that difficult - if you know which values you have to set with which content. Maybe one day we will get a great Graph SDK and a useful documentation :-)