Few days back, while trying to answer a question about a consent prompt for some application, I opened the Azure AD blade and noticed something puzzling. I don’t remember if this was a deliberate choice or by chance, but I clicked on the “MS Tech Comm” application, the one enabling us to login with Office 365 accounts to the Microsoft Tech Community. On the Permissions tab for the app, under User Consent, an empty entry was visible. By empty, I mean this:
Note the lack of Permission display name and Permission description values, pretty important ones if you ask me. And it turns out this isn’t a single/random occurrence, I was able to reproduce the exact same behavior by using a new tenant to access the MTC and provisioning the app. Moreover, other applications in my tenant seem to show the same trait, prime example being the Graph explorer application!
To try and understand whether this is a cosmetic issue or something more serious, I started looking into all the different methods we have to get the list of permissions granted to a given application. The good old MSOnline module can list the corresponding service principal object, but doesn’t have any method to display permissions. With the Azure AD module on the other hand we can leverage the Get-AzureADServicePrincipalOAuth2PermissionGrant cmdlet to get the permissions. I’ve even published a script that can help you enumerate all third party apps and their corresponding permissions. Here’s what I could get out of the Azure AD module in this case:
Scope : User.Read openid email profile offline_access
At first glance, nothing interesting. The subtle difference is the presence of another leading space character, right after the semicolon character. Since space is the separator used when returning permissions entries, this indicates that another, “empty” permission entry is present. In contrast, here’s how the Scope output would look for service principal that doesn’t have such entries:
Scope : Directory.Read.All User.Read
It becomes a bit easier to understand if you use the Select -ExpandProperty method in PowerShell or get the property directly:
PS C:\> (Get-AzureADServicePrincipalOAuth2PermissionGrant -ObjectId 2447dc5e-44d0-46b2-9d0e-cd5572ea4ca2).Scope
User.Read openid email profile offline_access
PS C:\> (Get-AzureADServicePrincipalOAuth2PermissionGrant -ObjectId f842c430-48bb-44d7-a67a-c0f60ce7d5f4).Scope
Directory.Read.All User.Read
In order to exclude the possibility that this is simply an oddity of the PowerShell representation of the permission object, I went and checked it with the Graph API directly. Here’s the result in JSON form:
{
"@odata.context": "https://graph.microsoft.com/beta/$metadata#oauth2PermissionGrants",
"value": [
{
"clientId": "5c5ee9b1-5343-434d-b683-8213a4d4267c",
"consentType": "Principal",
"expiryTime": "2019-09-28T17:34:31.6578813Z",
"id": "seleXENTTUO2g4ITpNQmfJrNnWjE96ZNgP_OmB9amDbX3p6kjBWNTL7nhv-T0LWk",
"principalId": "a49eded7-158c-4c8d-bee7-86ff93d0b5a4",
"resourceId": "689dcd9a-f7c4-4da6-80ff-ce981f5a9836",
"scope": " User.Read openid email profile offline_access",
"startTime": "0001-01-01T00:00:00Z"
}
]
}
Leading space again, so I’m not being crazy here. For comparison, another app representation via the Graph:
{
"@odata.context": "https://graph.microsoft.com/beta/$metadata#oauth2PermissionGrants",
"value": [
{
"clientId": "d6828122-1a97-46d8-be20-a72d7bf74604",
"consentType": "Principal",
"expiryTime": "2019-07-11T20:15:09.1639414Z",
"id": "IoGC1pca2Ea-IKcte_dGBIm2UOKu5f1NjPfelFES7OLh7ZAh7hDjQq9EXxSU0hSV",
"principalId": "2190ede1-10ee-42e3-af44-5f1494d21495",
"resourceId": "e250b689-e5ae-4dfd-8cf7-de945112ece2",
"scope": "User.Read Group.ReadWrite.All",
"startTime": "0001-01-01T00:00:00Z"
}
]
}
As already shown above, the Azure AD portal also treats this as an additional entry. On the other hand, the Cloud App Security portal seems to trim the leading space and only reports 5 permission entries (as opposed to the 6 entries visible in the Azure AD blade). The Azure AD Audit logs also seem to trim the leading space, so the mistery remains. The application consent screen itself only lists the default OIDC v2.0 scopes:
A quick checkup against the rest of the Azure AD integrated applications in my tenant shows few other entries that display the same behavior. And just to make sure that this is not yet another oddity specific to my tenant, I run it against few more, including a demo tenant. Interestingly enough, all of apps showing this behavior are authored by Microsoft. Here’s how to generate a list of such applications:
PS C:> Get-AzureADOAuth2PermissionGrant -All $true | ? {$_.Scope.StartsWith(" ")}
Application ConsentType User Scope
----------- ----------- ---- -----
MS Tech Comm Principal vasil@michev.info User.Read openid email profile offline_access
FastTrack Principal vasil@michev.info profile openid
Graph explorer Principal vasil@michev.info openid profile User.ReadWrite User.ReadBasic.All ...
OAuth Sandbox Principal pesho@michev.info openid offline_access profile Mail.ReadWrite Mail.ReadWrite.Shared ...
I’m not inclined to believe that Microsoft somehow allowed a “blank” scope, with no description or display name, so this is probably some minor code error causing a valid permission entry (or perhaps some “internal” one?) to be replaced by empty string, without removing the separator as well. Like in this example:
PS C:\> "a b c d"
a b c d
PS C:\> "a b c d".Replace("a","")
b c d
On the other hand, it might be something more serious, so I’ve probed some folks about it. Whatever this turns out to be, it would be nice if we had consistent display across all admin endpoints.