Being authenticated to Microsoft 365 tenant means Microsoft 365 knows who is trying to get access. To actually be able read/write or manage resource, your app must be Authorized to this resource.
For details – pls refer to MS authorization and Microsoft Graph API permissions. But again, in short in our case that means we need to have an API permission configured for our azure registered app. There are two kinds of API permissions – delegated and application.
Delegated permissions are intended to allow currently authenticated user to have access to the resource. Effective user permissions in this app would be an intersection of user own permissions and app permissions. So if an app have “Sites.FullControl.All” SharePoint delegated API permissions – that does not mean that user will have full control over all sites.
Here is an example of delegated permissions:
Permissions above allow you to search through SharePoint content being authenticated with your personal credentials. In search results you will see only content you already have access to.
Application permissions are what it says – once permissions are configured – application will have access to the resources according to API permissions.
Generally, application permissions allow an app to have access to all resources of the same kind in tenant, e.g. to get one specific groups owners an app must have “GroupMember.Read.All” permission that allows an app to read all tenant groups and their members. There are some exceptions – e.g. for Teams Microsoft developed RSC that allows scoped app access. For SharePoint there is a similar option – “Sites.Selected” API permissions.
API permissions must have an Admin consent. Here is an example of application permissions:
Permissions above allow your app to search all SharePoint content.
You are trying to register an application at SharePoint site with appregnew.aspx page and you are getting an error or notification message “Your SharePoint tenant admin doesn’t allow site collection admins to create an Azure Access Control (ACS) principal“.
Or you are trying to provide ACS-based permissions for an application to SharePoint site with appinv.aspx page and you are getting “Your SharePoint tenant admin doesn’t allow site collection admins to update app permissions. Please contact your SharePoint administrator.”
You can still view and even delete your apps permissions from /_layouts/15/appprincipals.aspx page:
Reason
This is due to a recent update to Microsoft 365 (tenant governance security measures enhancement MC660075) implemented by Microsoft in Aug/Sep 2023. According to the update, only tenant administrators can create or update ACS service principal by default.
The root cause for this is that the Microsoft is pushing developers out of that legacy ACS-based SharePoint Apps-only service principals towards Azure-registered applications with Sites.Selected API permissions as they are more secure etc. In Nov 2023 Microsoft announcement retirement of ACS principals.
Key differences between ASC and Sites.Selected are:
ACS-based SharePoint app/permissions
Apps registered in Azure with Sites.Selected API permissions
Support authentication with client secret only, Secrets are valid for 1 year exactly.
Support authentication with client secret and/or certificate, custom expiration time.
Support granular access to SharePoint site, e.g. to site collection or web (subsite) or a specific list or library.
Support only access to entire site collection (but Microsoft says granular access is coming) Granular permissions are available – ‘Lists.SelectedOperations.Selected’, ‘ListItems.SelectedOperations.Selected’ and ‘Files.SelectedOperations.Selected’ permissions allows to provide application access to list, library or list item or particular documents
Support only classic SharePoint REST API and CSOM
Support both – classic SharePoint REST API and CSOM and Microsoft Graph API
App id (client id) is created via appregnew.aspx at a specific SharePoint site by site collection administrator (disabled in Sep 2023).
App id (client id) is created in Azure portal (Entra Id), API Sites.Selected permissions are configured via Azure portal (Entra Id) and require tenant admin consent.
Permissions for the app to a site are provided at the site by site collection administrator via appinv.aspx page (disabled in Sep 2023).
Permissions for the App to to a specific SharePoint site are provided via Graph API by SharePoint admin with PowerShell script.
Solution #1 – switch to Sites.Selected
Register an application in Azure (via Entra Id – Azure portal GUI, PowerShell script or your company’s specific helpdesk/servicedesk request)
Update the app so both – MS Graph API Sites.Selected and SharePoint Sites.Selected permissions are configured, then
API permissions must be consented – so you’d seek/request your tenant admin consent
Obtain and upload client certificate (recommended) or generate client secret (at this moment you should be able to authenticate to tenant)
Request access for the app to a specific SharePoint site – your SharePoint service admin should be able to do that (at this moment you should be able to authorize to your SharePoint site).
Validate your app has access to the target SharePoint site with PowerShell (check validation scripts below under References).
Use recommended by Microsoft technique, code samples are available for the most popular languages/platforms – Python, C#, Java etc. (check below under References).
Secure your certificate and/or secret. It is not a good idea to use hard-coded secrets, so consider using special services/storages for secrets (aka Vaults)
If you are hosting your application in Azure – consider using managed identity.
There are 3-rd party (and Microsoft) apps developed using classic approach (examples – Azure data Factory, Alteryx). So in some cases Sites.Selected permissions are not enough to get access to SharePoint.
Solution #2 – admin to register/update an ACS app
This option is acceptable if you have existing application that require ACS-based access. This option is not recommended for new development, as ACS is deprecated and scheduled for retirement.
Microsoft (MC660075 in Message Center): “site collection admin will be unable to register app or update app permissions through above pages unless authorized explicitly by the SharePoint tenant admin” and “With this update site owners will not be able to register/update apps unless the tenant admin explicitly allows it.”
That is incorrect. Site collection admin cannot register app (appregnew) or provide permissions to the app (appinv) anymore. Tenant admin does not authorize site collection admins. Instead tenant (or SharePoint) admin can register an app or provide permissions to the app at a specific site (not changing the entire default behavior back…). But there was no such option (!) in the middle of October 2023, when this feature was enabled at all tenants. Even having a SharePoint admin or tenant admin permissions – if you tried to register an app with AppRegNew.aspx – you got the same error message “Your SharePoint tenant admin doesn’t allow site collection admins to…”.
Later (Checked today – Nov 6, 2023) it seems like Microsoft has implemented it! E.g. now SharePoint or tenant admin is able to register an app with AppRegNew.aspx or update it with AppInv.aspx at any specific site collection. SharePoint or tenant admin must also be among this site collection admins.
It is ok (and I’d say the preferred way) to provide ACS permissions to the app registered in Azure, so do not register apps in SharePoint anymore (do not use AppRegNew.aspx).
Bottom line: if ACS-based permissions are required for app here you go:
register application in Azure (Entra id)
activate your SharePoint service/tenant admin role
ensure you are also target site collection administrator
navigate to the site appinv.aspx page – e.g. “https://yourtenant.sharepoint.com/sites/yoursite/_layouts/15/appinv.aspx” and us Azure registered app (client) Id. E.g. for lookup provide
Azure registered app (client) Id for – click lookup
localhost as app domain
https://localhost as redirect url
Permission Request XML – depending on permissions you need, e.g. for full app access to entire site collection:
It is possible to switch back this new default behavior that prevents site collection admin to register/update apps at SharePoint. This is done with PowerShell command
To run this command – you’d need to be a SharePoint service or tenant admin.
But this will be a step back on your journey in improving m365 tenant safety, as after that you’ll have a self-registered service principals out of control again. So devs will be using it not being aware of ACS retirement and when Microsoft switch off ACS – it will be a disaster, as all app will stop working. That is why Microsoft implemented this feature to soft-disable ACS and allowed us 2 years to redesign or apps and migrate from ACS to Entra Id apps with Sites.Selected. So this solution is not recommended.
In case you really need an exception to provide an ACS-based service principal – there is Solution number 2.
Full text of Microsoft’s MC660075 message
(Updated) SharePoint admin control for App registration / update
Tag MAJOR UPDATE ADMIN IMPACT FEATURE UPDATE
Message Summary Updated August 30, 2023: We have updated the content below for clarity. Thank you for your patience.
This is an enhancement to the security measures for administrative governance that modifies the default procedures for SharePoint app registration via AppRegNew.aspx page and permission updates via AppInv.aspx page. Following the implementation of this change, site collection admin will be unable to register app or update app permissions through above pages unless authorized explicitly by the SharePoint tenant admin.
Upon attempting to register an application on AppRegnew.aspx page, a notification will be displayed stating “Your SharePoint tenant admin doesn’t allow site collection admins to create an Azure Access Control (ACS) principal. Please contact your SharePoint tenant administrator.”
Similarly, upon attempting to update app permissions on AppInv.aspx page, a notification will be displayed stating “Your SharePoint tenant admin doesn’t allow site collection admins to update app permissions. Please contact your SharePoint tenant administrator.”
Kindly note that app registration and permission update via Microsoft Azure portal are not impacted by this change.
When this will happen:
The rollout process is scheduled to commence in late August and is expected to conclude in mid-September.
How this will affect your organization:
With this update site owners will not be able to register/update apps unless the tenant admin explicitly allows it.
To modify the default behavior, the tenant administrator must execute the following shell command to explicitly establish the flag as TRUE, thereby superseding the default value of FALSE. The service principal can only be created or updated by the tenant administrator by default. However, when the flag is set to TRUE, both the SharePoint tenant admin and site collection admin will be able to create or update the service principal through SharePoint.
The shell command is: Set-SPOTenant -SiteOwnerManageLegacyServicePrincipalEnabled $true
Note: The property ‘SiteOwnerManageLegacyServicePrincipalEnabled’ becomes visible in tenant settings after SharePoint Online Management shell is updated to 16.0.23710.12000 or a later version. But before this rollout, the value will always be TRUE even explicitly set to FALSE. It will only automatically be switched to FALSE as the default value after the rollout is launched.
What you need to do to prepare:
No proactive measures are required to prepare for this change. Nevertheless, it is advisable to inform your users of this modification and update any relevant documentation as necessary.
Sites.Selected permissions are required for the non-interactive applications to get access to a specific SharePoint site using Microsoft Graph API and/or SharePoint API. (Since Microsoft announced EOL of SharePoint App-only service principals, Sites.Selected is the only option going forward). Below are
Historically, we utilized so called SharePoint app-only service principals to get unattended (daemon/service) access to one specific site programmatically. Initially in on-prem, later in SPO. SharePoint app-only service principals use ACS-based authentication and allow calls to SharePoint (REST) API and usage of SharePoint CSOM.
Then Microsoft started developing Graph API. You’d need to register your app in Azure to get App Id and App secret to authenticate to Microsoft Graph API. You’d also configure specific API permissions for this app to get access to services you need. Unfortunately, for a long time there were no options to get access to only one specific site with Graph API. Available API permissions allowed access to entire SharePoint only.
Then, in 2021 Microsoft introduced Graph API “Sites.Selected” application permissions. Hooray! The problem was dev had to have two service principals – new Sites.Selected to call Graph API and classic SP-App-only to call SharePoint API. Later, in 2022 Microsoft implemented SharePoint “Sites.Selected” API permissions… More on this…
Long story short, below are the detailed steps to configure Sites.Selected for you unattended app access to SharePoint site.
Steps to get and configure Sites.Selected permissions
1. Register an application in Azure (Entra Id) via Azure portal GUI, PowerShell script or helpdesk/servicedesk request. E.g. with GUI you’d login to portal.azure.com, the search for “App registrations” and select “+ New registration”:
If you are not allowed to register an Entra Id app due to permissions restrictions in your company – connect with your IT/admins, as there must me some way to request an app.
Once you get an application registration – you are this app owner now – you should be able to navigate to your app registration and configure it (see Step 2 and below).
2. Update the app “API permissions” – so both – MS Graph API Sites.Selected and SharePoint Sites.Selected application API permissions are configured:
Request tenant admin consent for your API permissions. Finally your app registration “API permissions” should look like:
3. App Secret or Certificate Under Certificates and secrets – generate client secret, copy secret value to safe location.
Or you can obtain trusted (or create a self-signed) certificate, and upload it to your app registration. Certificates are considered as more secure option then secrets.
4. At the Overview page – grab your app client id and tenant id :
At this moment, having tenant id, app (client) id and client secret (or certificate) – you should be able to authenticate against Microsoft 365 tenant with app-only authentication path.
But! Having just Sites.Selected API permissions configured for app does not mean your app has access to any SharePoint site. Access for the app to a specific site is provided by SharePoint team via Graph API calls. That leads us to the next step.
5. Application access to SharePoint site You need to request this from your SharePoint service admin (or if you are an admin – DIY), but access needs to be provided for the specific app to the specific site with specified permissions (Read-Only or Read/Write or Manage or Full Control) – Here is the Graph API – Here is PowerShell PNP cmdlet
Obviously, Read role allows an app to read site content; Write role is similar to “Contributor” user permissions – it allows CRUD operations against list items (library documents and metadata), but does not allow create/update/delete lists/libraries (for this – you’d need Manage role).
Use Sites.Selected permissions
Once your SharePoint tenant/service admin confirmed that access has been provided – you can use app client id and client secret (or certificate) to work with SharePoint from your code using Graph API. There are some good tutorials published:
Generally, this Sites.Selected permissions allows you to make calls that are documented under “Files” and “Sites and Lists” Graph API documentation. I.e. get site details, get site lists/libraries, create lists and libraries, CRUD operations against list items, download/upload library documents – all within the specific site. Sites.Selected permissions does not allow search operations, anything related to group or team etc.
If you have concerns if permissions for your app were provided correctly or not – you can validate your app access to the target SharePoint site with simple PowerShell scripts: here is the sample code
Note: Sites.Selected API permissions allows you call Microsoft Graph API with client Id and client secret. Calling SharePoint API with client secret is not supported. You have to use client id and certificate to call SharePoint API having app with Sites.Selected permissions.
Call SharePoint API with client Id and client secret is possible only if ACS-based permissions are provided for the app to the site, which is not recommended due to announced retirement (see below).
Secure your credentials
You do not want to hard-code your client secret as you do not want your credentials be leaked. So you need to secure your secrets in production. Solutions for secrets are included in cloud providers offerings, you can also use GitHub environment variables. If you are hosting your application in Azure – consider using key vault to keep your secrets. You can configure managed identity for your application and provide access to the key vault for you application managed id.
Govern Sites.Selected permissions
(For SharePoint admins).
Existing admins API/cmdlets allows yo to provide Sites.Selected permissions for specific app to specific site, and to get Sites.Selected permissions provided to the specific site. But there is no API/cmdlet for the specific app to get all sites (with permissions) this app has access to. Meantime as SharePoint admin if you keep providing permissions upon users/devs requests – after some time you have no idea what app has access to what site with which level of access, especially in large organizations.
Surely you can (and should) pull reports on all registerd apps with access to SharePoint, but…
There is a solution developed by Joe Rodgers (Microsoft). This solution use SharePoint list as an inventory/storage and Power Automate flows to pull data from Entra Id and SharePoint and provides kind of dashboard so you can review details of all app registrations in the tenant with at SharePoint Online permission. Cool!
Note: you would not provide Sites.Selected permissions just upon user/developer request. You’d always get an approval from target site owner. Target site owner must understand that application will have permanent unattended access to entire SharePoint site with permissions specified (read or write or manage or full control).
Generally, to provide an Application with Sites.Selected API permissions configured access to a specific site, SharePoint admin would run a set of PowerShell commands (or C# program or…) to ensure the client id exists, API permissions are configured and consented, to get app owners, target site owners, to get existing app permissions etc. Finally, admin would provide permissions and validate that permissions were provided correctly. It does not take long…
Update: Microsoft announced decommissioning of ACS permissions. So using ACS for any new development is not recommended.
It may be acceptable to grant ACS permissions to existing custom applications or third-party or Microsoft apps/web apps (e.g. Alteryx, Azure Data Factory) – applications that only support a client ID and secret and use the SharePoint API under the hood – but only to avoid disruption to business processes and keeping in mind that ACS will expire soon, so these applications must be replaced/updated before 2026.
Update: Microsoft implemented granular (permissions to list, item or file) alongside with Sites.Selected permissions. Original implementations of Sites.Selected allowed access to entire site collection only. With new ‘Lists.SelectedOperations.Selected’, ‘ListItems.SelectedOperations.Selected’ and ‘Files.SelectedOperations.Selected’ permissions it is possible to provide application permissions to list, library or list item or particular document (reference).
There are well-known SharePoint app-only service principals and ACS-based permissions. It is kind of old-school way – introduced as part of Add-Ins for SharePoint 2013 – to get unattended access to SharePoint site (application access, i.e. access without user presence). Such apps are called daemon apps or service apps or background jobs etc…
Microsoft announced retirement of ACS in 2026 and takes measures to stop using ACS in new and existing tenants. For you to smoothly switch to new, recommended Entra Id based service principals and permissions – it is important to know some details about classic app-only service principals and ACS-based permissions.
As you know, any access is a two-step procedure:
Authentication, when systems ensures you are indeed the one you claim you are
Authorization, when system grants you access to the resource, as it knows that this id is allowed to access such and such resource with these permissions
So, when it comes to deprecated SharePoint app-only service principals and ACS-based permissions, AppRegNew is responsible for authentication and AppInv is responsible for authorization.
AppRegNew.aspx
To get a SharePoint app-only service principal – you’d need to register a new one at any SharePoint site using the AppRegNew.aspx page. This page is not available from GUI, so you’d need to type the Url manually. You’d need to be a site collection admin to register a new app.
Let say, your site Url is “https://YourTenant.sharepoint.com/teams/YourSite“. Then this appregnew page’s Url would be “https://YourTenant.sharepoint.com/teams/YourSite/_layouts/15/appregnew.aspx“
If you go to this page, you’ll see (*) something like
You’d click generate client id, then generate client secret and type your app display name. I usually use “localhost” as app domain and “https://localhost” as redirect Url.
If all good – you’d get app id (client id) and app secret (client secret) and you’d be able to authenticate to your SharePoint site.
AppInv.aspx
Providing permissions for your SharePoint app-only service principal to your SharePoint site is done using AppInv.aspx page. This page is also not available from GUI, so you’d need to type the Url manually again. You’d need to be a site collection admin to use this page.
Let say, your site Url is “https://YourTenant.sharepoint.com/teams/YourSite“. Then this appinv page’s Url would be “https://YourTenant.sharepoint.com/teams/YourSite/_layouts/15/appinv.aspx“
If you go to this page, you’ll see (*) something like
At this moment – you need to enter app (client) id here and click lookup – so all the app metadata would be populated, then you’d need to enter Permission Request XML. Via this “Permission Request XML” you are specifying exact permissions your app will have in this site. E.g. you can specify scope – all site collection or one specific subsite (web) or even one specific list or library. Also you can specify permissions level – e.g. read, read/write, manage or full control. This is tricky, but let me share some examples with you.
Permission Request XML for the app to have full control over entire site collection:
Any mistake in XML might prevent app access, so be very careful.
Finally, your AppInv.aspx page would look like
If you specify scope as web – you’d do it on the specific web url, e.g. “https://YourTenant.sharepoint.com/teams/YourSite/SubSite/_layouts/15/appinv.aspx”
If you specify scope as list – you’d do it on the specific web url, e.g. “https://YourTenant.sharepoint.com/teams/YourSite/SubSite/_layouts/15/appinv.aspx” and after you click “Save” – there will be a page – you’ll be asked to choose a list from available web lists.
After all, you’ll be asked to confirm that you trust the app:
And after that your app (SharePoint app-only service principal) will have access (ACS-based access) to you site.
AppPrincipals.aspx
From site settings page (/_layouts/15/settings.aspx) you should be able to see apps registered on your site with “Site app permissions” or “Site collection app permissions” links available via GUI. That would be “appprincipals.aspx” page.
Unfortunately, you cannot see you app permissions here or your secret expiration time. Some date can be pulled via PowerShell with Get-PnPAzureACSPrincipal
Possible complications
After Microsoft announced retirement of ACS – you can see this message on appinv and appregnew pages:
You might also see “Your SharePoint tenant admin doesn’t allow site collection admins to create an Azure Access Control (ACS) principal” message at appregnew page and “Your SharePoint tenant admin doesn’t allow site collection admins to update app permissions. Please contact your SharePoint administrator.” at appinv page.
That’s because a recent update to Microsoft 365 (MC660075) pushed by Microsoft in Aug/Sep 2023 changes default behavior so only tenant administrators can create or update ACS service principal by default.
Update: Sites.Selected API MS Graph permissions was introduced by Microsoft in 2021. It was a good move towards site-level development, but still developers were limited with only what MS Graph API provides for SharePoint dev. So devs had to use AppInv.aspx at site level to provide ACS permissions to their apps to be able to use SharePoint CSOM and REST APIs. Recently Microsoft introduced Sites.Selected SharePoint API permissions for registered Azure Apps! So now devs should be fully happy without ACS-based permissions.
Scenario
You have an application that needs access to Microsoft 365 SharePoint Online site/list/documents. Application is running without interaction with users – e.g. unattended, as daemon job.
There are two options you can authenticate to Microsoft 365 – with the secret or with the certificate. Authenticating with certificate is considered more secure.
Questions
What happens if SharePoint-Apps only principal is disabled (i.e. ‘set-spotenant -DisableCustomAppAuthentication $true’ )?
Why I’m getting 401 error when authenticating to SPO?
Why I’m getting 403 error when authenticating to SPO with secret?
What permissions to I need to work with SPO?
Findings
Note: we will use PowerShell 7.2 and PnP.PowerShell 1.9 to illustrate it.
Disabled SharePoint-Apps only principal
If SharePoint-Apps only principal is disabled in your tenant (i.e. ‘Get-PnPTenant | select DisableCustomAppAuthentication’ returns $true ), then the only way you work with SPO from code is:
an App registered in Azure
API permissions provided via Azure (MS Graph, SharePoint)
Certificate is used
In all other cases (even your Connect-PnPOnline command complete successfully) – you will be getting error 401 (unauthorized) when trying Get-PnPTenant or Get-PnPTenantSite or Get-PnPSite
Enabled SharePoint-Apps only principal
If SharePoint-Apps only principals are enabled in your tenant (i.e. ‘Get-PnPTenant | select DisableCustomAppAuthentication’ returns $false ), then you have three options to work with SPO from code:
Azure App with a secret (Client Id + Client Secret) and permissions to SharePoint provided via SharePoint (AppInv.aspx) to access SharePoint REST API
Azure App with a certificate (Client Id + Certificate) and permissions provided via Azure to access SharePoint REST API
Azure App with a certificate or secret (Client Id + Secret or Certificate) and permissions provided via Azure to access SharePoint via Microsoft Graph API
You have a Microsoft 365 subscription with SharePoint Online. You use PowerShell, PnP.PowerShell module and MS Graph API to work with SharePoint under current user’s credential. You need to authenticate to SharePoint Online via Connect-PnPOnline and to Microsoft Graph API interactively on behalf of a current user.
Problem
Unfortunately, both “Connect-PnPOnline -Interactive -Url <siteUrl>” or “Connect-PnPOnline -UseWebLogin -Url <siteUrl>” might fail with something like “Need admin approval”, “App needs permission to access resources in your organization that only an admin can grant. Please ask an admin to grant permission to this app before you can use it.” or “Permissions requested” or similar
configure API permissions blade: – add delegatedpermissions you need (refer to specific API you’ll use) e.g. Microsoft Graph Sites.FullControl.All and SharePoint AllSites.FullControl
A pop-up window will appear to authenticate interactively. If you are already authenticated with another credentials (or single-sigh-on) – an interactive window might pop up and disappear – that prevents you enter your other id. To ensure Connect-PnPOnline prompts you for your credentials – use ” -ForceAuthentication” option.
If you are a SharePoint tenant admin – you can connect to a tenant with:
By default token expires in ~ 1 hour. But you can refresh it silently. This helps you in long-running PowerShell scripts that takes hours to complete. So you can include something like this in the loop:
Somehow using Connect-PnPOnline with AccessToken option did not work if the token was acquired with MSAL.PS interactively. But it did work when you get msal.ps token unattended (using App credentials). So…
If you can get an Application (non Delegated) permissions to your azure-registerd-app, you can use msal token to connect to site with PnP
=========================
NB: For delegated permissions, the effective permissions of your app are the intersection of the delegated permissions the app has been granted (via consent) and the privileges of the currently signed-in user. Your app can never have more privileges than the signed-in user.