Call SharePoint REST API inside Azure Fucntion on .NET 8 is causing this error "Response status code does not indicate success: 401 (Unauthorized)."
We have an Azure Function that runs on a scheduled basis, and we have enabled its managed identity. Using this identity, we've successfully integrated the function with both Azure SQL database and Azure Key Vault by assigning the necessary permissions:
We are now looking to integrate the same Azure Function with SharePoint Online, to enable read and write operations to specific site.
We run those commands based on this article from Microsoft @ https://learn.microsoft.com/en-us/sharepoint/dev/apis/webhooks/sharepoint-webhooks-using-azd-template#grant-the-function-app-access-to-sharepoint-online:-
# 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
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
Now we should have granted the Azure function the required permission to access the SharePoint site using SharePoint REST API + Graph API.
I have this code in my Azure Function which uses 2 ways for authenticating:
- If I am on my development machine, I will authenticate using the browser
- If I am in the Azure Function hosted app, I will authenticate using the Azure Function identity
When I run the project on my development machine, I get this error:-
Response status code does not indicate success: 401 (Unauthorized).
Here is the full code:
var allItems = new List<CallTransferLogData>();
while (!string.IsNullOrEmpty(fullUrl))
{
var response = await httpClient.GetAsync(fullUrl);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(content);
var root = doc.RootElement.GetProperty("d");
// Parse items
var items = root.GetProperty("results");
foreach (var item in items.EnumerateArray())
{
var parsed = new CallTransferLogData
{
VID = item.GetProperty("Title").GetString(),
SRBrokerName = item.GetProperty("field_4").GetString(),
Log = item.GetProperty("field_5").GetString(),
YourName = item.GetProperty("field_3").GetString(),
Email = item.GetProperty("Email").GetString(),
Timestamp = item.GetProperty("field_0").GetDateTime(),
IfLogIsTODAYLeaveThisBlank = item.GetProperty("field_2").GetDateTime(),
SharePointSourceID = item.GetProperty("ID").GetInt32()
};
allItems.Add(parsed);
}
// Get next page
fullUrl = root.TryGetProperty("__next", out var nextLink)
? nextLink.GetString()
: null;
}
if (allItems.Count == 0)
{
_logger.LogInformation("No Call Transfer Log Data found.");
//return;
}
//Insert/Update Conversations in SQL Server
await UpsertCallTransferHistoryLogToSqlServer(allItems);
_logger.LogInformation("Call Transfer Log Data successfully processed.");
await SQLInteraction(new Log { Status = "End Call Transfer Log Data TimeJob Execution Successfully" }, false);
}
catch (Exception ex)
{
_logger.LogError($"Error: {ex.Message}");
anyexception = true;
await SendEmail("ATTN Ruben-Azure Function Exception-Call Transfer Log Data", ex.Message, Environment.GetEnvironmentVariable("ToEmailException"));
await SQLInteraction(new Log { Status = "End Call Transfer Log Data TimeJob with Exception", Exception = ex.Message }, false);
}
Any advice why we get this unauthorized error?