PS >cloudkreise

Just unnecessarily complicated: The Graph API application and service principal


There are some ongoing confusions around the meaning, usage and purpose of the application and the serviceprincipal endpoint in Graph API. To make matters worse even microsoft is sometimes misleading in their documentations and therefore even other third parties like terraform in their registry.

Whats our starting point?

In Entra ID we have two very important buttons on our right side of our graphical user interface. If you expand the “applications” menu if will reveal the “enterprise applications” and the “app registrations”. Sometimes both lists lists the same applications, sometimes not. Why is that?

Furthermore if you use the Graph API or the Graph API PowerShell Module, things will get a little bit confusing in microsofts naming scheme.

Lets see what I mean:

If we browse to the enterprise application blade and take a look at the number it will list me in a fresh “Microsoft Entra ID” tenant about 600+. If we then try to query the list with help of Graph API via Graph Explorer or PowerShell, we only get two items.

GET https://graph.microsoft.com/v1.0/applications?$count=true

{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#applications",
    "@odata.count": 2,
[...]
}

When we browse instead to our app registrations it will make much more sense and we will find the same number of items there. We can now assume that with applications Microsoft means app registrations and not enterprise apps. But how do we find the enterprise apps then?

GET https://graph.microsoft.com/v1.0/serviceprincipals?$count=true

{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#servicePrincipals",
    "@odata.count": 610,
[...]
}

Microsoft decided back in the days to name the service principals in the Azure Active Directory Entra ID portal enterprise applications to simplify the user experience and clarify the functionality for IT administrators and users who may not be familiar with the more technical term service principal. For my beliefs I think hey have overshot the mark and it caused way more confusion then it tried to solve – especially with administrators.

What is an application then?

An so called application represents the main application object in our Entra ID tenant. An application object is a registered application and contains all the metadata and configuration details for that app. An application object is created once and exists only in our tenant. You use it to access or configure the main application object like the application’s name, redirect URIs and API permissions or client secrets.

And a Service principal?

A service principal represents an instance of an application in a specific tenant and is used to configure tenant-specific settings for an application. It’s created when an application is used in another tenant. Service principals exist in every tenant that requires access to the application, including the home tenant and is handling things like permissions, roles, and tenant-specific settings. Maybe you remember the setting of the supported account types – there you configure if a service principal could be used by third parties.

Step by step …

Imagine our company wants to use a SaaS-Application like Adobe Creative Cloud that integrates with Entra ID for Single Sign-On and identity management.

In the home tenant of Adobe they register their application in their Entra ID. This creates an application object in their Entra ID tenant, including metadata like redirect URIs, permissions and a service principal. This service principal is used to identify Adobe Creative Cloud globally, across all other tenants that use the application.

After Adobe “published” their SaaS-Application we have to add it to our own Entra ID tenant. The service principal is a representation of the Adobe Creative Cloud application specific to our tenant and it has its own unique ID in our tenant. More on that later. The service principal part in our tenant carries configuration settings for our specific use of the app, including permissions, user assignments or SCIM settings.

If a user now clicks on the Single Sign-On Button at Adobe Creative Cloud he will be redirected to our tenant where he needs to verify his identity. After that Entra ID will look up the service principal in our tenant and check the configuration like the permissions granted to this specific user. Furthermore is is checked if the service principal is allowed to request the needed information for that requested process like reading the users profile to display the correct name.

After successful authentication, Entra ID issues an access token (and optionally an ID token) which is send to Adobe Creative Cloud to get validated. The user has then successfully logged in and can use the application with the appropriate permissions defined by the service principal. Hurray!

So the AppID points to the is the App Registration, right? Nope.

When using the Portal, the PowerShell Modules or the Graph API directly, we will notice about a bunch of different called IDs. There are IDs, Object IDs, AppIDs, Client IDs and so on. I will try to explain these and match the command line output to the graphical user interface.

When we search for an service principal aka Enterprise App in Entra ID, the following IDs are important:

  • AppId
    • … is the unique identifier for the service principal and the same across all Entra ID tenants.
  • AppOwnerOrganizationId
    • … is a unique identifier (GUID) that corresponds to the Entra ID tenant where the application object was originally registered and is being managed. In our example it would point to the Entra ID tenant from Adobe.
  • Id
    • … is a Unique identifier for a specific object like an application or a service principal in your own Entra ID tenant.
Get-MgServicePrincipal -filter "DisplayName eq 'Demo Application'" `
| fl AppDisplayname,AppId,AppOwnerOrganizationId,Id


AppDisplayName         : Demo Application
AppId                  : 9605a4bc-ac73-465d-a233-f726e5f752e6
AppOwnerOrganizationId : db027721-ffed-4d88-8619-70500a3632d9
Id                     : 4c2df924-2ba3-42f3-b6a6-55f49fbec000
Get-MgApplication -Filter "DisplayName eq 'Demo Application'" `
| fl DisplayName,AppId,Id


DisplayName : Demo Application
AppId       : 9605a4bc-ac73-465d-a233-f726e5f752e6
Id          : 047acfdc-e6fa-4bd8-bedf-f7f0db00b101

If you try to search for a service principal with Get-MgServicePrincipal you would assume to use the unique identifier for it – the AppId. Microsoft sees things differently and wants the Object ID or simply ID with the parameter ServicePrincipalId.

Get-MgServicePrincipal -ServicePrincipalId "9605a4bc-ac73-465d-a233-f726e5f752e6"

Get-MgServicePrincipal : Resource '9605a4bc-ac73-465d-a233-f726e5f752e6' does not exist or one of its
queried reference-property objects are not present.
Status: 404 (NotFound)
ErrorCode: Request_ResourceNotFound
[...]
Get-MgServicePrincipal -ServicePrincipalId "4c2df924-2ba3-42f3-b6a6-55f49fbec000" `
| fl AppDisplayname,AppId,AppOwnerOrganizationId,Id

AppDisplayName         : Demo Application
AppId                  : 9605a4bc-ac73-465d-a233-f726e5f752e6
AppOwnerOrganizationId : db027721-ffed-4d88-8619-70500a3632d9
Id                     : 4c2df924-2ba3-42f3-b6a6-55f49fbec000

If you now try to search for an application using the Get-MgApplication command with the ApplicationId parameter, you will probably feel tempted to use the AppID. But no, Microsoft wants here the Object ID of the app registration and not the Application ID (also called Client ID).

Get-MgApplication -ApplicationId "9605a4bc-ac73-465d-a233-f726e5f752e6"

Get-MgApplication : Resource '9605a4bc-ac73-465d-a233-f726e5f752e6' does not exist or one of its queried
reference-property objects are not present.
Status: 404 (NotFound)
ErrorCode: Request_ResourceNotFound
[...]
Get-MgApplication -ApplicationId "047acfdc-e6fa-4bd8-bedf-f7f0db00b101" `
| fl Displayname,AppId,AppOwnerOrganizationId,Id


DisplayName : Demo Application
AppId       : 9605a4bc-ac73-465d-a233-f726e5f752e6
Id          : 047acfdc-e6fa-4bd8-bedf-f7f0db00b101

If you want to find an app registration with the Application ID (also called Client ID), you have to use the filter parameter in combination with the AppId attribute with it.

Get-MgApplication -Filter "AppId eq '9605a4bc-ac73-465d-a233-f726e5f752e6'" `
| fl Displayname,AppId,Id

DisplayName : Demo Application
AppId       : 9605a4bc-ac73-465d-a233-f726e5f752e6
Id          : 047acfdc-e6fa-4bd8-bedf-f7f0db00b101

And if you want to find an service principal with the Application ID (also called Client ID), you have to use the filter parameter in combination with the AppId attribute with it.

Get-MgServicePrincipal -Filter "AppId eq '9605a4bc-ac73-465d-a233-f726e5f752e6'" `
| fl Displayname,AppId,AppOwnerOrganizationId,Id

DisplayName            : Demo Application
AppId                  : 9605a4bc-ac73-465d-a233-f726e5f752e6
AppOwnerOrganizationId : db027721-ffed-4d88-8619-70500a3632d9
Id                     : 4c2df924-2ba3-42f3-b6a6-55f49fbec000

Lets recap the last one …

  • The Object ID for a app registration or a service principal is simply called Id with the Get-MgApplication or Get-MgServicePrincipal and is unique in your tenant.
  • The AppId is the Application ID (also called Client ID) for a service principal, that is globally unique.
  • The parameter ApplicationID with Get-MgApplication wants the Object ID and not the Application ID (also called Client ID).
  • The paremter ServicePrincipalId with Get-MgServicePrincipal wants the Object ID and not the Application ID (also called Client ID).

Wow. That was unnecessarily complicated. Thank you Microsoft.