How to setup SharePoint Online Sites.Selected permissions

How to setup SharePoint Online Sites.Selected permissions

Last updated on February 15, 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. 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, Sites.Selected scope was introduced to address this issue. When using this permission scope, you can specify at the site level which permissions your app has on that site. Great huh?

The process of granting these permissions is two-fold:

  1. Grant the Sites.Selected permission for your Azure app’s managed identity to the SharePoint Online API as you normally would.
  2. Add the permission your app needs on a specific site to the site 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 may also wish to 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.
However, this blog post is about granting permissions for the SharePoint Online API, and thus, we are going to grant the Sites.Selected permission as the other more restrictive permissions are only available for Microsoft Graph.

Granting the Sites.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, SharePoint, Exchange Online, and Power BI are the same across all tenants, so I’ve listed them in the comments for easy reference. Here, we need to target SharePoint Online.

We also specify the permissions we need. In this case, the permission scope is Sites.Selected, which allows us to scope access only to the SharePoint sites we specify later rather than granting blanket access to the entire tenant.

Now, because this script will most likely not be run by us but instead by an admin, they may not yet have the required PowerShell modules installed on their machine. Before proceeding any further, the script 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 SharePoint Online 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.

Granting the site specific permissions

Now, you might be wondering: “We granted the managed identity the Sites.Selected permission to SharePoint Online, but how do we actually select which sites 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 the list of SharePoint site URLs 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.

We also specify the permission level we want to grant on the sites. The options are read, write, owner, or 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.

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 site URLs and use the Grant-PnPAzureADAppSitePermission commandlet to grant our app’s managed identity the specified permission on the sites. This is the command that creates the connection between Sites.Selected and the specific sites we want our Azure app to access.

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



Leave a Reply

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