There is a well-known and well-documented way of connecting to Microsoft 365 SharePoint and Graph API from Azure Function App via keeping credentials (Client id and client secret) in the Azure Key Vault. In this article I explained how to configure Azure Key Vault so Azure Function can get credential and use them to access Microsoft 365 SharePoint and call Graph API. For this to work we need an App registration with permissions provided. But what if we assign permissions directly to the Function App?
As per Microsoft, managed identities enable Azure resources to authenticate to cloud services (e.g. Azure Key Vault) without storing credentials in code. Is it possible to use function managed identity to access Microsoft 365 SharePoint via PnP or Graph API? Follow me.
I assume we already have an Entra Id, a Microsoft 365 subscription in it and an Azure subscription in the same tenant.
Create a User Assigned Managed Identity
There are two types of managed identities in Azure – System assigned and user assigned.
If you go to Azure Function app -> Settings -> Identity – you’ll see these two options:

- System assigned Managed Identity will be created automatically if you select Status:On and Save. Having System-assigned Managed Identity you can provide permissions to Azure resources (e.g. storage, key vault) to this specific instance of function app. If you create another function app that’d need the same access – you’d need to enable system assigned Managed Identity again, for this new instance and again provide permissions.
- User assigned managed identity is created as standalone Azure resource, and will have it’s own lifecycle. A single Azure resource (e.g. Function App) can utilize multiple user assigned managed identities. Similarly, a single user assigned managed identity can be shared across multiple resources. So if you deploy another Function App that need the same permissions as your existing function app – you’d just assign the same managed identity to this new function app.
So before we assign a user-assigned managed identity to a resource, we need to create a user-assigned managed identity:

For the Name of your User Assigned Managed Identity consider something that would uniquely identify you (your team) and your project/app at tenant level, e.g. “m365-Enterprise-SharePoint-Engineering-Managed-Identity-Demo”:

Create and Configure a Function App
Create your function app as you usually do that. (If you want to kill two birds with one stone – create a function app with “App Service” – aka Dedicated plan – you’ll see how to secure your function app storage account access with Managed Identity).
I use PowerShell Core as runtime stack and Windows.
Once Function App is created – we need to create a function. I’ll do it via Azure Portal for simplicity and I’ll select timer-triggered function:

Ensure that this function works ootb correctly by triggering test run:

Then we’d need to assign a managed identity earlier created to this function app.
Navigate to Function App -> Settings -> Identity, select “User Assigned” and managed identity:

Disable Az
Navigate to Function App -> Functions -> App Files. Select “profile.ps1”.
Remove or comment out part that use Az module cmdlets:

Update function dependencies
Since I use PowerShell and PnP for this demo, I need PnP module loaded.
Navigate to Function App -> Functions -> App Files. Select “requirements.psd1”. Update your code by adding ‘PnP.PowerShell’ = ‘2.12.0’ to the required modules. Do not enable Az module:

It takes time for the function app to download and install PnP module so you can use it in functions.
Update function code
Add the following code to function:
# My custom code
Write-Host "My custom code started"
$siteUrl = "https://jvkdev.sharepoint.com/sites/Test101"
$UserAssignedManagedIdentityObjectId = "b0bfe72c-73a9-4072-a78b-391e9670f4b9"
Write-Host "Connecting..."
$connection = Connect-PnPOnline $siteUrl -ManagedIdentity -UserAssignedManagedIdentityObjectId $UserAssignedManagedIdentityObjectId -ReturnConnection
Write-Host "Connection:"
$connection
Write-Host "Getting site:"
Get-PnPSite -connection $connection
Now you can Test/run the function or wait 5 minutes, then check what is in logs. You should see, that
- connection ran successfully, but
- getting site failed with “ERROR: The remote server returned an error: (401) Unauthorized.”
And that is ok, as
- With Connect-PnPOnline we are authenticating. And since managed id exist – we were recognized
- Our managed Id does not have any permissions yet, so any request will fail
Now it’s time to provide actual permissions for the managed identity to the site.
Grant permissions for the managed identity to access SharePoint via Graph API
Here is the most interesting part – somehow we need to provide our user assigned managed identity with permissions to access SharePoint (or any other Microsoft 365 service) via Microsoft Graph API and/or SharePoint API. We already know how to grant permissions to an App Registration in Azure – there is a GUI for that. But with respect to managed identity – there is no GUI. It’s done via Microsoft Graph API or PowerShell. And we need admin permissions to assign roles to a managed identity.
Who can grant roles to a managed identities
It says a Global Admin permissions required to provide roles to a managed identity.
As usual, there are two options: delegated permissions and application permissions (here is where differences explained). In both cases you’d need an App Registration with the following API permissions assigned and consented :
- Application.Read.All (or higher)
- AppRoleAssignment.ReadWrite.All
If you have an app with delegated permissions – you’d need a Global admin role to be activated. Or you need an app with application permissions configured as below:

If you are getting something like this:

That means you configured an app incorrectly.
Assigning permissions with Microsoft Graph API:
tbp…
Assigning permissions with PnP PowerShell
Here is the code:
$Id = "..." # User Assigned Managed Identity Object Id = Principal Id
Get-PnPAzureADServicePrincipalAssignedAppRole -Principal $Id
$role = "Sites.FullControl.All"
Add-PnPAzureADServicePrincipalAppRole -Principal $Id -AppRole $role -BuiltInType MicrosoftGraph
Add-PnPAzureADServicePrincipalAppRole -Principal $Id -AppRole $role -BuiltInType SharePointOnline
tbc