We have an Azure Function on .NET 8.0. and we enabled the managed identity of the Azure Function. Then we run those commands as per this official MS link https://learn.microsoft.com/en-us/sharepoint/dev/apis/webhooks/sharepoint-webhooks-using-azd-template#grant-the-function-app-access-to-sharepoint-online:-
Power shell command:
# This script requires the modules Microsoft.Graph.Authentication, Microsoft.Graph.Applications, Microsoft.Graph.Identity.SignIns, which can be installed with the cmdlet Install-Module below:
# Install-Module Microsoft.Graph.Authentication, Microsoft.Graph.Applications, Microsoft.Graph.Identity.SignIns -Scope CurrentUser -Repository PSGallery -Force
Connect-MgGraph -Scope "Application.Read.All", "AppRoleAssignment.ReadWrite.All"
$managedIdentityObjectId = "d3e8dc41-94f2-4b0f-82ff-ed03c363f0f8" # 'Object (principal) ID' of the managed identity
$scopeName = "Sites.Selected"
$resourceAppPrincipalObj = Get-MgServicePrincipal -Filter "displayName eq 'Office 365 SharePoint Online'" # SPO
$targetAppPrincipalAppRole = $resourceAppPrincipalObj.AppRoles | ? Value -eq $scopeName
$appRoleAssignment = @{
"principalId" = $managedIdentityObjectId
"resourceId" = $resourceAppPrincipalObj.Id
"appRoleId" = $targetAppPrincipalAppRole.Id
}
New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $managedIdentityObjectId -BodyParameter $appRoleAssignment | Format-List
And this pnp command:
Connect-PnPOnline -Url "https://YOUR_SHAREPOINT_TENANT_PREFIX.sharepoint.com/sites/YOUR_SHAREPOINT_SITE_NAME" -Interactive -ClientId "YOUR_PNP_APP_CLIENT_ID"`
Grant-PnPAzureADAppSitePermission -AppId "3150363e-afbe-421f-9785-9d5404c5ae34" -DisplayName "YOUR_FUNC_APP_NAME" -Permissions Manage
Here is the code for the Azure Function, which uses the login user credential if I am inside development machine and uses the Azure Function managed identity on the hosted app:
if (Environment.GetEnvironmentVariable("AZURE_FUNCTIONS_ENVIRONMENT") == "Development")`
{
var credential = new InteractiveBrowserCredential(); // or AzureCliCredential
graphClient = new GraphServiceClient(credential);
}
else
{
var credential = new DefaultAzureCredential(); // Managed Identity
graphClient = new GraphServiceClient(credential);
var token = await new DefaultAzureCredential().GetTokenAsync(
new TokenRequestContext(new[] { "https://graph.microsoft.com/.default" })
);
_logger.LogInformation("Token acquired: " + token.Token.Substring(0, 20) + "...");
}
//Call to get the "Call Transfer Log Data" sharepoint list data`
try
{
var sitePath = "e**87";
var listId = "6*`*`*`*`";
var allItems = new List<ListItem>();
// Initial page request with Expand = fields
var page = await graphClient
.Sites[sitePath]
.Lists[listId]
.Items
.GetAsync(config =>
{
config.QueryParameters.Top = 100;
config.QueryParameters.Expand = new string[]{ "fields($select=*)" };
});
allItems.AddRange(page?.Value ?? []);
// code goes here...
}
Then I verified the setting, but running this command:
Get-PnPAzureADAppSitePermission -Site "<Site URL>"
I get this result:
Id : ***...-....
Roles : {Manage}
App : Microsoft.Azure.Functions – 3150363e-afbe-421f-9785-9d5404c5ae34
Also the :-
_logger.LogInformation("Token acquired: " + token.Token.Substring(0, 20) + "...");
will return a number, which means the token is been generated..
In the development environment, the code is working fine, while in the hosted Azure Function, the code raised an exception:
Access Denied
Any advice? It seems I use all the needed settings.
Thanks

AllSites.FullControlin scope and check