How to set up Microsoft Graph and SharePoint Online *.Selected API permissions

How to set up Microsoft Graph and SharePoint Online *.Selected API permissions

Last updated on July 27, 2026

In the past, whenever your application required certain permissions on a SharePoint Online site, you’d need to grant those permissions to the entire tenant, even if your app only needed access to a single site, list, list item or document. From a security standpoint, this does not follow the best practice that is the “principle of least privilege”, i.e., granting the minimum required permissions for the app to operate. Luckily, the Sites.Selected scope was introduced to address this issue, and these days we have even more fine-grained permission scopes on Microsoft Graph. When using these *.Selected permission scopes, you can specify at the site, list, list item and file level which permissions your app has on those exact resources. Great huh?

The process of granting these permissions is two-fold:

  1. Grant the *.Selected permission for your Azure app’s managed identity to the API as you normally would.
  2. Add the permission your app needs to the specific site, list, list item or file entity.

Because we developers rarely have admin privileges on customer tenants, this entire process should be made as effortless as possible for the customer’s admin to perform. That is why I wrote a couple of scripts for accomplishing this task, which require nothing more than the admin to execute them (after you’ve specified the correct variable values). And because sharing is caring, here I am, sharing them with you.

SharePoint Online REST API vs Microsoft Graph API

The Sites.Selected permission is available on both SharePoint Online and Microsoft Graph APIs. Which API you should grant permissions for depends on which API the code you are going to execute uses. Even though Microsoft Graph is the API of choice, not all operations are available on that API, so calling the SharePoint Online API is still required in many situations.

If your code uses Microsoft Graph, you can narrow the permissions further to one of the following scopes. Instead of granting access to the entire site, you can grant permissions to only certain lists, folders, files or list items. The fewer permissions the app has, the better (as long as it can still do what it needs to).

  • Lists.SelectedOperations.Selected: Manage access on a list level. Grants access to the specified lists.
  • ListItems.SelectedOperations.Selected: Manage access on a folder/file/list item level. Grants access to the specified list items.
  • Files.SelectedOperations.Selected: Manage access on a folder or file level. Grants access to the specified files.

Granting the *.Selected permission

If you’ve ever tried to grant API permissions to a managed identity, you’ve probably already noticed that you can’t do it through the Entra ID portal the same way you would for a regular app registration. There’s simply no button for it. Instead, we need to turn to PowerShell.

First, we need to define a few variables: our tenant ID, the managed identity object ID for our Azure app, and the API app ID we want to grant permissions to. The app IDs for Microsoft APIs like Graph and SharePoint are the same across all tenants.

We also specify the permissions we need. Remember, only the Sites.Selected permission is available for the SharePoint Online REST API. Microsoft Graph supports the Sites.Selected scope as well as the three more narrow scopes.

Now, because this script will most likely not be run by us but instead by an admin, we need to consider that they may not run the script with PowerShell 7 or have the required PowerShell modules installed on their machine. Before proceeding any further, the script ensures that it is run with the correct PowerShell version and checks whether the Microsoft.Graph.Applications PowerShell module is installed. If it isn’t, the admin will get a prompt to install it.

Next, the script asks the admin to authenticate to Microsoft Graph interactively through their browser. The scopes requested (AppRoleAssignment.ReadWrite.All and Application.Read.All) are the permissions needed to assign app roles to the managed identity.

Once connected, the script looks up the API service principal in Entra ID. Then, it loops through the permissions we specified and creates a role assignment that essentially says: “Grant this permission for this API to this managed identity.”

If the assignment succeeds, the admin will get a nice green confirmation in the console. If the permission already exists, the script catches that specific error and displays a yellow message instead of blowing up. Any other unexpected errors are thrown as-is, so we don’t accidentally swallow something important.

If you later need to remove (some of) the permissions, you can do so with the following script: remove-selected-permissions.ps1

Granting the resource specific permissions

Now, you might be wondering: “We granted the managed identity the *.Selected permission, but how do we actually specify which resources it can access?” An excellent question! That’s exactly what this second script is for.

We start by defining our variables: the tenant name, the name of our Azure app (used as a descriptive display name for the permission entry), the Application ID of the managed identity, and a list of the SharePoint resources we want to grant access to. One thing to be careful about here is that we need the Application ID of the managed identity, not the Object ID. You can find it in Entra ID under enterprise applications by filtering for managed identities and searching by name. Alternatively, you can use the managed identity object ID to search for the application ID in the same view.

We also need to specify the permission level we want to grant on the resources. The options are read, write, owner, and fullcontrol. The options are listed from the least permissive to the most permissive. You only need to specify a single permission because the less permissive scopes are always included in the more permissive permission levels. Also, if your app uses both Microsoft Graph and SharePoint Online APIs, you have granted the Sites.Selected scope for both, and you want your app to access the same site via both APIs, you only need to provide a single permission (the more permissive one) to cover both. There’s no API specific separation here.

The script uses the PnP.PowerShell module, so we first check whether the PnP.PowerShell module is already installed, and prompt the admin to install it if it isn’t.

Next comes a step that might look a little unfamiliar: we register an Entra ID application for PnP.PowerShell using the Register-PnPEntraIDApp commandlet. This is needed because these days, PnP.PowerShell requires its own single-tenant app registration on the target tenant for authentication. In the past, it was a multi-tenant app that was not as secure.

The app is granted the AllSites.FullControl scope as a delegated permission, so that the script is able to add the selected permission scope on the specified sites on the admin’s behalf.

Once the app registration is in place, the script prompts the admin to authenticate using the newly registered app and then connects to the SharePoint tenant admin site.

Finally, we loop through the list that specifies what permissions should be granted for which resources, and use the Grant-PnPEntraIdApp*Permission commandlets to grant our app’s managed identity the specified permissions. This is the part that creates the connection between *.Selected permission and the specific resource we want our Azure app to access.

If you later need to remove (some of) the permissions, you can do so with the following script: revoke-resource-specific-permissions.ps1

Afterword

That’s it: two neat little setup scripts for admins that they can easily run and get the job done. After running both scripts, our managed identity has exactly the access it needs. No more, no less. Just as it should be to achieve security best practices.

If you run into any issues, have questions, or just want to share your experience, feel free to leave a comment below. And if you’d like to get notified when I publish new posts, you can subscribe to my blog via the sidebar and/or follow me on LinkedIn.

Thanks for reading, and until next time!

Laura



2 thoughts on “How to set up Microsoft Graph and SharePoint Online *.Selected API permissions”

  • Hi there!

    Very nice script, saved me a lot of time, thank you! Only correction, that will save even more time, is on line 64. It is calling for variable “$permission” when it was defined as “$permissions” at the start.

    • Thanks for the heads up, Tommi! The scripts have now been updated to support the more fine-grained Graph permissions, so this issue has also been fixed.

      Laura

Leave a Reply

Your email address will not be published. Required fields are marked *