{"id":7464,"date":"2024-01-02T16:59:39","date_gmt":"2024-01-02T16:59:39","guid":{"rendered":"https:\/\/rakhesh.com\/?p=7464"},"modified":"2024-01-02T16:59:39","modified_gmt":"2024-01-02T16:59:39","slug":"delegating-app-registration-admin-consent-permissions-in-azure-ad-using-graph-an-example-for-sites-selected","status":"publish","type":"post","link":"https:\/\/rakhesh.com\/azure\/delegating-app-registration-admin-consent-permissions-in-azure-ad-using-graph-an-example-for-sites-selected\/","title":{"rendered":"Delegating App Registration Admin Consent permissions in Azure AD using Graph (an example for Sites.Selected)"},"content":{"rendered":"

This is a continuation of an older post <\/a>and an example<\/a>.<\/p>\n

This<\/a> and this<\/a> posts from Microsoft are useful references too.<\/p>\n

I want to delegate the ability to do admin consents to certain Graph permissions to some of my admins. In this case the “Sites.Selected” Graph API permission which typically needs a Global Admin to do the consent. To do this I have to create a custom app consent policy and a custom role that includes this app consent policy.<\/p>\n

First, connect to Graph with the following scopes.<\/p>\n

Connect-MgGraph -Scopes \"Policy.Read.PermissionGrant\",\"Policy.ReadWrite.PermissionGrant\",\"RoleManagement.ReadWrite.Directory\"<\/pre>\n

Get the Microsoft Graph service principal.<\/p>\n

$servicePrincipal = Get-MgServicePrincipal -All | Where-Object { $_.DisplayName -eq \"Microsoft Graph\" }<\/pre>\n

For reference, here’s an example of the output:<\/p>\n

> Get-MgServicePrincipal -All | Where-Object { $_.DisplayName -match \"Graph\" }\r\n\r\nDisplayName                                           Id                                   AppId                                SignInAudience      ServicePrincipalType\r\n-----------                                           --                                   -----                                --------------      --------------------\r\nIDML Graph Resolver Service and CAD                   2362f192-9721-4089-b2c9-6acf3e9ce553 d88a361a-d488-4271-a13f-a83df7dd99c2 AzureADMultipleOrgs Application\r\nGraph Data Connect App Registration                   2a911a15-76e9-4e98-a1ee-f9f45bd6eba2 52e6d66a-9b02-477b-ad84-01c7d088f081 AzureADMyOrg        Application\r\nExchange Office Graph Client for AAD - Noninteractive 2f4d6758-e00b-4037-a933-8b5224f00489 765fe668-04e7-42ba-aec0-2c96f1d8b652 AzureADMultipleOrgs Application\r\nMicrosoft Graph                                       327ba63b-334e-4004-bb30-20a607de4098 00000003-0000-0000-c000-000000000000 AzureADMultipleOrgs Application\r\nAzure Graph                                           40a924a5-b3b2-45d3-b466-cc5b2cbf9884 dbcbd02a-d7c4-42fb-8c27-b07e5118b848 AzureADMultipleOrgs Application\r\nExchange Office Graph Client for AAD - Interactive    57943d81-ce4c-4a80-ae3f-56ce03c6a8fd 6da466b6-1d13-4a2c-97bd-51a99e8d4d74 AzureADMultipleOrgs Application\r\nAudit GraphAPI Application                            68420e79-2754-4dbd-9819-7049a2820601 4bfd5d66-9285-44a1-bb14-14953e8cdf5e AzureADMultipleOrgs Application\r\nMicrosoft Graph PowerShell                            70a6c76d-5c6b-41ca-bb81-56d6f0360ec0 14d82eec-204b-4c2f-b7e8-296a70dab67e AzureADandPersonal\u2026 Application\r\nMicrosoft Graph Change Tracking                       895b3d4b-d0b6-4102-8e01-d19ad243a7df 0bf30f3b-4a52-48df-9a82-234910c4a086 AzureADMultipleOrgs Application\r\nMicrosoft Teams Graph Service                         9479fa7c-c94a-4c73-8599-92b762ac0029 ab3be6b7-f5df-413d-ac2d-abf1e3fd9c0b AzureADMultipleOrgs Application\r\nOfficeGraph                                           9b00ad24-77e1-4d53-be39-19e1bf08aa0d ba23cd2a-306c-48f2-9d62-d3ecd372dfe4 AzureADMultipleOrgs Application\r\nAzure Resource Graph                                  adaf502e-f36c-4163-af9d-46ecf592d482 509e4652-da8d-478d-a730-e9d4a1996ca4 AzureADMultipleOrgs Application\r\nGraph Connector Service                               bea6ee98-3321-47f5-aff4-4f4844c68c35 56c1da01-2129-48f7-9355-af6d59d42766 AzureADMultipleOrgs Application\r\nMicrosoft Graph Connectors Core                       ec34f212-7d53-4c21-b153-c623b96877e6 f8f7a2aa-e116-4ba6-8aea-ca162cfa310d AzureADMultipleOrgs Application<\/pre>\n

I selected the Microsoft Graph one from above.<\/p>\n

Get the permission Id of the “Sites.Selected” permission within this.<\/p>\n

$permissionId = ((Get-MgServicePrincipal -ServicePrincipalId $servicePrincipal.Id).AppRoles | Where-Object { $_.Value -eq \"Sites.Selected\" }).Id<\/pre>\n

Here’s an example of what the permission looks like:<\/p>\n

> (Get-MgServicePrincipal -ServicePrincipalId $servicePrincipal.Id).AppRoles | Where-Object { $_.Value -eq \"Sites.Selected\" }\r\n\r\nAllowedMemberTypes   : {Application}\r\nDescription          : Allow the application to access a subset of site collections without a signed in user.The specific site collections and the permissions granted will be configured in SharePoint\r\n                       Online.\r\nDisplayName          : Access selected site collections\r\nId                   : 883ea226-0bf2-4a8f-9f9d-92c9162a727d\r\nIsEnabled            : True\r\nOrigin               : Application\r\nValue                : Sites.Selected\r\nAdditionalProperties : {}<\/pre>\n

Now create a new app consent policy and add the “Sites.Selected” permission within it.<\/p>\n

New-MgPolicyPermissionGrantPolicy `\r\n    -Id \"mytenant-graph-sites-selected\" `\r\n    -Description \"Permissions consentable by Application administrator (Sites)\" `\r\n    -DisplayName \"Only sites.selected permission\"\r\n\r\nNew-MgPolicyPermissionGrantPolicyInclude `\r\n    -PermissionGrantPolicyId \"mytenant-graph-sites-selected\" `\r\n    -PermissionType \"application\" `\r\n    -ResourceApplication $servicePrincipal.AppId `\r\n    -Permissions $permissionId<\/pre>\n

Here’s what the policy looks like:<\/p>\n

> Get-MgPolicyPermissionGrantPolicy -PermissionGrantPolicyId 'mytenant-graph-sites-selected' | fl *\r\n\r\nDeletedDateTime      :\r\nDescription          : Permissions consentable by Application administrator (Sites)\r\nDisplayName          : Only sites.selected permission\r\nExcludes             : {}\r\nId                   : mytenant-graph-sites-selected\r\nIncludes             : {f934e25e-6b38-4045-b690-8e2ba42c2915}\r\nAdditionalProperties : {[@odata.context, https:\/\/graph.microsoft.com\/v1.0\/$metadata#policies\/permissionGrantPolicies\/$entity], [includes@odata.context,\r\n                       https:\/\/graph.microsoft.com\/v1.0\/$metadata#policies\/permissionGrantPolicies('mytenant-graph-sites-selected')\/includes], [excludes@odata.context,\r\n                       https:\/\/graph.microsoft.com\/v1.0\/$metadata#policies\/permissionGrantPolicies('mytenant-graph-sites-selected')\/excludes]}<\/pre>\n

Now to create a custom role that includes this app consent policy.<\/p>\n

$params = @{\r\n\tdescription = \"Can manage selected SharePoint app registrations permissions\"\r\n\tdisplayName = \"Application administrator (SharePoint)\"\r\n\trolePermissions = @(\r\n\t\t@{\r\n\t\t\tallowedResourceActions = @(\r\n                \"microsoft.directory\/applications\/basic\/read\",\r\n                \"microsoft.directory\/applications\/createAsOwner\",\r\n                \"microsoft.directory\/servicePrincipals\/allProperties\/read\",\r\n                \"microsoft.directory\/applications.myOrganization\/allProperties\/read\",\r\n                \"microsoft.directory\/applications.myOrganization\/allProperties\/update\",\r\n                \"microsoft.directory\/servicePrincipals\/create\",\r\n                \"microsoft.directory\/servicePrincipals\/managePermissionGrantsForSelf.mytenant-graph-sites-selected\",\r\n                \"microsoft.directory\/servicePrincipals\/managePermissionGrantsForAll.mytenant-graph-sites-selected\"\r\n\t\t\t)\r\n\t\t}\r\n\t)\r\n\tisEnabled = $true\r\n}\r\n\r\nNew-MgRoleManagementDirectoryRoleDefinition -BodyParameter $params<\/pre>\n

I had to make some tweaks here compared to when I first did this in 2021<\/a>. Specifically, I added these two:<\/p>\n

                \"microsoft.directory\/applications.myOrganization\/allProperties\/read\",\r\n                \"microsoft.directory\/applications.myOrganization\/allProperties\/update\",<\/pre>\n

Just the update one would have been enough, I think. I came across this list from Microsoft’s app registrations permissions page<\/a>. This other page with permissions for app consent <\/a>is where I across the last two permissions.<\/p>\n

                \"microsoft.directory\/servicePrincipals\/managePermissionGrantsForSelf.mytenant-graph-sites-selected\",\r\n                \"microsoft.directory\/servicePrincipals\/managePermissionGrantsForAll.mytenant-graph-sites-selected\"<\/pre>\n

This is what allows the Delegated and Application permissions to be consented, for “Sites.Selected”.<\/p>\n

Now grant this to an admin from the portal.<\/p>\n

\"\"<\/p>\n

Now Adele can login to the portal, create an app registration, add the “Sites.Selected” permission, remove the “User.Read” permission (coz that is not something we allowed in the list above), and do an admin consent (I had to refresh the page after adding the permission, for the “Grant admin consent” button to show).<\/p>\n

\"\"<\/p>\n

 <\/p>\n","protected":false},"excerpt":{"rendered":"

This is a continuation of an older post and an example. This and this posts from Microsoft are useful references too. I want to delegate the ability to do admin consents to certain Graph permissions to some of my admins. In this case the “Sites.Selected” Graph API permission which typically needs a Global Admin to … Continue reading Delegating App Registration Admin Consent permissions in Azure AD using Graph (an example for Sites.Selected)<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[887],"tags":[1031,1024,1016,1015],"jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/posts\/7464"}],"collection":[{"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/comments?post=7464"}],"version-history":[{"count":1,"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/posts\/7464\/revisions"}],"predecessor-version":[{"id":7470,"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/posts\/7464\/revisions\/7470"}],"wp:attachment":[{"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/media?parent=7464"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/categories?post=7464"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/tags?post=7464"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}