Before we can make search call to Microsoft 365 in our code – we need to be authenticated.
There are many kinds of authentication flows Microsoft supports. For more details – please refer to Microsoft Identity Platform documentation but in short – there are two kind of authentications – as current user and as daemon application and in both cases we need an application registration in Azure.
Briefly here is what you need to have for your custom application to authenticate to Microsoft 365:
configure Secrets or Certificates (for daemon apps)
Register Application in Microsoft Azure
1. You’d go to https://portal.azure.com/ 2. Type app registration in search and select App registration
3. Select “New registration”
4. For now, you’d just need to provide your application display name and leave other fields as default – Single tenant and no redirection Url, then click “Register”
5. If you are seeing an error message telling that your are not allowed to register an app – you’d reach your AAD/EntraId/Global admins so they can register an app for you.
6. Under Azure Portal App Registrations you should be able to see your app:
7. Under Overview blade notice you Client Id and tenant Id:
Configure Authentication blade for interactive apps
Azure apps for interactive authentication are configured differently (check MS app types and authentication flows) for different scenarios/platforms.
Here is a good article from MS. Microsoft Graph quick start can register an app for you. Microsoft publish tutorials for .net, Go, Java, JavaScript, PHP, Python, TypeScript…
In a few words, you’d need to add Platform as below
manually if you know how to configure it. Otherwise, Quickstart and/or Integration assistant might help you.
You do not need Certificates or Secrets for authentication as current user.
Configure Secrets or Certificates for daemon apps
Daemon apps (aka service apps, also called background jobs) – all kind unattended access scenarios do not require configuration under Authentication blade – but require Secrets or Certificate. You’d need to be familiar with certificates, as certificates considered as more secure way to authenticate and some authentication flows allow secrets, but some require certificates.
So for daemon apps you need a secret and/or certificate:
Here is how I configure daemon app for PowerShell.
Having an app configured as above – you should be able to authenticate against Microsoft 365 Graph API, but should not have access to resources, as app is not authorized yet.
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.
You run some PnP PowerShell code unattended e.g. daemon/service app, background job – under application permissions – with no user interaction. Your app needs to connect to SharePoint and/or Microsoft Graph API. Your organization require authentication with a certificate (no secrets). You want certificate stored securely in Azure Key Vault.
Solution (Step-by-step process)
Obtain a certificate (create a self-signed or request trusted)
In Azure where you have Microsoft 365 SharePoint tenant
Create a new Registered App in Azure; save App (client) id, Directory (Tenant) Id
Configure App: add MS Graph and SharePoint API application (not delegated) permissions
Upload the certificate to the app under “Certificates & secrets”
In Azure where you have paid subscription (could be same or different)
Create an Azure Key Vault
Upload certificate to the Key Vault manually (with GUI)
While you develop/debug your custom daemon application at your local machine
Provide permissions to the Key Vault via Access Control and Access Policies to your personal account
Connect to Azure (the one where your Key Vault is) running Connect-AzAccount – so your app can get a Certificate to authenticate to SharePoint Online
For your application deployed to Azure (e.g. Azure Function App )
Turn On managed identity (Your Function App -> Identity -> Status:On) and Save; notice an Object (Principal) Id just created
Provide for your managed identity principal Id permissions to the Key Vault via Key Vault Access Policies, so when your daemon app is running in the cloud – it could go to the key Vault and retrieve Certificate
Here is the sample PowerShell code to get certificate from Azure Key Vault and Connect to SharePoint with PnP (Connect-PnPOnline):
# ensure you use PowerShell 7
$PSVersionTable
# connect to your Azure subscription
Connect-AzAccount -Subscription "<subscription id>" -Tenant "<tenant id>"
Get-AzSubscription | fl
Get-AzContext
# Specify Key Vault Name and Certificate Name
$VaultName = "<azure key vault name>"
$certName = "certificate name as it stored in key vault"
# Get certificate stored in KeyVault (Yes, get it as SECRET)
$secret = Get-AzKeyVaultSecret -VaultName $vaultName -Name $certName
$secretValueText = ($secret.SecretValue | ConvertFrom-SecureString -AsPlainText )
# connect to PnP
$tenant = "contoso.onmicrosoft.com" # or tenant Id
$siteUrl = "https://contoso.sharepoint.com"
$clientID = "<App (client) Id>" # Azure Registered App with the same certificate and API permissions configured
Connect-PnPOnline -Url $siteUrl -ClientId $clientID -Tenant $tenant -CertificateBase64Encoded $secretValueText
Get-PnPSite