Azure AD schema and directory extensions

Updated: Jun 23, 2020

In a similar way to on-premises Active Directory (AD), Azure AD has a schema that defines a set of objects that can be created in the directory (tenant). Associated with each object type is a property (attribute) set. Some properties need to be populated to create the object, other property values are set to provide additional information about the subject.

On many occasions, an application can have specific requirements to store additional information about Azure AD object types such as users, group and devices. This additional information could be stored in an external database and the data linked to Azure AD objects using an immutable identifier such as the Azure AD object identifier. Alternatively, the data can be stored in Azure AD.

I was asked by a customer to recommend the best way of storing a custom attribute in Azure AD. Before I could make the recommendation, I had to do some research. In this blog, I will share with you the results of that work, it’s a long read, but hopefully you will find it informative.

There are three ways of adding additional attributes to Azure AD.

  • Azure AD Graph Extensions

  • Microsoft Graph Open Extensions

  • Microsoft Graph Schema Extensions

Stay tuned, and I will delve into this complex and intriguing subject. In addition to extending the directory to store the additional attribute values, you will discover how some extension properties can be synchronized from on-premises AD and can be added to SAML, ID and Access tokens.

Introduction to the Azure AD schema

Figure 1 illustrates the definition of a user object in the Azure AD schema and an instance of the user object in the directory.

Image showing the role of the Azure AD directory schema

The schema defines the type of data for each attribute, for example, Edm.String, Edm.DateTime, Edm.Boolean, etc. Edm refers to the entity data model, which describes structured data. When creating a user object in the directory, values must be defined for specific attributes. The creator of the user object must choose some attribute values, and others are automatically set by Azure AD. For instance, when creating a user object, you have to supply a valid UserPrincipalName and DisplayName. Azure AD fills all the other properties required to instantiate the user object. In most situations, the creator of the object wants to populate more attributes than the minimum necessary for the creation of the object.

If you are familiar with on-premises AD, then you might well have used the Schema Manager (Figure 2) to examine the AD Schema.

Image showing on-premises AD Schema Manager

The on-premises AD has a schema which you can directly view and understand the relationship between the AD objects and attributes. If you are looking for the same in Azure AD, you will be disappointed; there is no way to view the schema directly. With Azure AD, you will need to rely on documentation for the definition of objects and their associated properties. Programmatic access to the directory is through a Graph API, and there are currently two different APIs. Azure AD Graph and Microsoft Graph you can view the documentation for a user object accessed via the Azure AD Graph API here and via the Microsoft Graph API here.

Microsoft Graph is replacing Azure AD graph and for the Azure AD supports many new datasets and features. Any applications that are currently using the Azure AD Graph API should be updated to use the Microsoft Graph API. In addition to access to Azure AD, Microsoft Graph is the API gateway to Microsoft 365 services. You can find the Microsoft Graph documentation here.

If you use the two different APIs to view the same object, you can get different views of the object. I have tried to illustrate this in Figure 3.

Illustration of the Azure AD API and the Microsoft API

Although you could be accessing the same object, the Microsoft Graph API can give you access to attributes that are not available via the Azure AD API. You may also discover that a property can have a different name depending on which API you use. For instance, the attribute that holds a value linking a synchronized user to their on-premises identity is called immutableId via the Azure AD Graph API and the onPremisesImmutableId via the Microsoft Graph API.

An Azure AD Graph query for$filter=startswith(userPrincipalName,'')&$select=userPrincipalName, immutableId&api-version=1.6


To get the same data returned with Microsoft Graph you need to use:$filter=startswith(userPrincipalName,'')&$select=userPrincipalName, onPremisesImmutableId


To query Microsoft Graph, you can use Graph Explorer; alternatively, you could use Postman (my personal favourite) for both queries to Microsoft Graph and Azure AD Graph. Postman has the advantage of importing and exporting collections. A collection is a collection of API calls, Microsoft has published a Microsoft Graph Postman collection. Read this document to get started.

Azure AD Graph directory schema extensions

Although the Microsoft recommendation is to use Microsoft Graph, you should understand the original Azure AD Graph extensions as these are used when synchronizing custom attributes from on-premises AD.

The property types that can be added are Binary, Boolean, DateTime, Integer, LageInteger and String. Extension attributes can be added to User, Group, TenantDetail, Device, Application and ServicePrincipal objects. For example, you could create a named property of type string that can be used with user, group and device objects.

New extension properties are registered on an application object. Think of an application object as a template definition of the application. Before the application can be used for authentication and authorization, a service principal (SP) is created in the tenant. For a single-tenant app, the application object and SP are in the same tenant. For a multi-tenant app, there is a single application object in the tenant where the app is defined. For each tenant that uses the application, an SP is created in that tenant. The SP is usually created when a user consents to the application. For a single-tenant, the SP is created when the app is registered through the Azure AD Portal. The application template is created in the Portal App registrations blade, and the SP is shown in the Enterprise applications blade.

Although extension properties can be registered on an application object, they cannot be used until the application's SP exists. Once the SP is created in a tenant, the extension properties are usable in that tenant. The extension properties can be read/managed by any application that has the appropriate permissions.

Figure 4 illustrates the relationship between extension properties, application objects, service principals and the objects to which the extension properties apply.

Illustration of how Azure AD Graph extensions work

The name of the extension property includes the application id of the application object. For example, if the Application (client) ID is 21695f38-e621-473b-93cf-215065a34b91 the extension property name is extension_21695f38e621473b93cf215065a34b91_CostCentre

If the SP is deleted from the tenant, the extension properties defined on the associated application object become inaccessible. If the SP is recreated, they once again become visible with their previously held values. When a property is set for a particular object, it counts against a quota limit of 100 extension property values for that object. The quota applies regardless of whether the property is visible or not. A properties value must be explicitly set to null to remove it from the quota count.

Although these extension properties are referred to as Azure AD extension properties, they can be managed through the Azure AD Graph API and the Microsoft Graph APIs, but here I will show you how to manage extensions on user objects through PowerShell. For other object types, you will need to resort to Graph.

To create an extension property, you will need an application to add it to. I have an API application called Myapi-19

$appName = 'Myapi-19'

$appObjId = (Get-AzureADApplication -SearchString $appName).Objectid

New-AzureADApplicationExtensionProperty -ObjectId $appObjId -Name "CostCentre" -DataType "String" -TargetObjects 'User' ##Note: The Targetobjects values are casesensitive

After running the above commands, the extension has been added to Myapi-19. You can enumerate all the extensions defined on an application using:

Get-AzureADApplication -ObjectId $appObjId | Get-AzureADApplicationExtensionProperty | fl

The results from running the command are:

Provided an SP for the application has been instantiated you can set and remove extension values on a user object.

$userUpn = ''

#Change an extension property value - reload the user to view the change

Set-AzureADUserExtension -ObjectId $userUpn -ExtensionName "extension_21695f38e621473b93cf215065a34b91_CostCentre" -ExtensionValue "Marketing"

#Read all extension attributes values on a user object

Get-AzureADUserExtension -ObjectId $Userupn


(Get-AzureADUser -ObjectId $userUpn).ToJson()

#Read a single extension property value

(Get-AzureADUserExtension -ObjectId $Userupn).get_item("extension_21695f38e621473b93cf215065a34b91_CostCentre")