Connecting Azure Function to SharePoint list using Azure Function managed Identity sometime raise "There has been an error authenticating the request.";category="invalid_client""

john john Pter 1,040 Reputation points
2025-04-26T09:27:04.3166667+00:00

I have an Azure Function which we enabled its managed Identity, as follow:-

User's image

then we run those commands, to allow the azure function to access SharePoint using the Azure Function managed identity, based on this technical documentation https://learn.microsoft.com/en-us/sharepoint/dev/apis/webhooks/sharepoint-webhooks-using-azd-template#grant-the-function-app-access-to-sharepoint-online:-

Script for Site.Selected

# 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 = "****" # '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

& Script for Sites.FullControl.All

# 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 = "****" # 'Object (principal) ID' of the managed identity
$scopeName = "Sites.FullControl.All"
$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 finally,

Connect-PnPOnline -Url "https://YOUR_SHAREPOINT_TENANT_PREFIX.sharepoint.com/sites/HR" -Interactive -ClientId "YOUR_PNP_APP_CLIENT_ID" 
Grant-PnPAzureADAppSitePermission -AppId "***" -DisplayName "YOUR_FUNC_APP_NAME" -Permissions Manage

now here is the code to connect to the SharePoint list:-

string accessToken = await GetJwtTokenUsingSystemManagedIdentity();

 string siteUrl = "https://**.sharepoint.com/sites/HR";

 string listName = "Call Transfer Log Data";

 string tenant = "***";

 string site = "analytics";

 string listTitle = "Call Transfer";

 siteUrl = $"https://{tenant}.sharepoint.com/sites/{site}";

 string apiBaseUrl = $"{siteUrl}/_api/web/lists/GetByTitle('{listTitle}')/items";

 var httpClient = new HttpClient();

 httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

 httpClient.DefaultRequestHeaders.Accept.ParseAdd("application/json;odata=verbose");

 string filterDate = DateTime.UtcNow.AddDays(-120).ToString("yyyy-MM-ddTHH:mm:ssZ");

 string requestUrl = $"{apiBaseUrl}?$filter=Modified ge datetime'{filterDate}'&$top=100&$orderby=Modified desc";

 bool hasMore = true;

 int page = 1;

 List<CallTransferLogData> responseContent = new List<CallTransferLogData>();

 while (hasMore)

 {

     Console.WriteLine($"Fetching page {page}...");

     var request = new HttpRequestMessage(HttpMethod.Get, requestUrl);

     var response = await httpClient.SendAsync(request);

     Console.WriteLine($"row response = " + response);

     string content = await response.Content.ReadAsStringAsync();

     using JsonDocument doc = JsonDocument.Parse(content);

     

     var root = doc.RootElement.GetProperty("d");

     Console.WriteLine($"Building Root {page}...");

     // Process results

     foreach (var item in root.GetProperty("results").EnumerateArray())

     { //code goes here

     }

}

        private static async Task<string> GetJwtTokenUsingSystemManagedIdentity()

        {

            string resource = "https://***.sharepoint.com/.default";

            var credential = new DefaultAzureCredential();

            var tokenRequestContext = new TokenRequestContext(new[] { resource });

            var token = await credential.GetTokenAsync(tokenRequestContext);

            //Console.WriteLine("Toekn is " + token.Token)

;            return token.Token;

        }

Now the azure function is suppose to run each day at 4 & 6 am UTC(). where yesterday at 11 pm UTC() , i deployed the azure function and to test it, i set its execution time to be 11:15 PM UTC(), and worked well, it got the items from SharePoint. then i modify the azure function to run at 4 & 6 am utc(). but today at 8 am UTC() i checked the logs and the call to SharePoint failed wit this exception:-

row response = StatusCode: 401, ReasonPhrase: 'Unauthorized', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:

x-ms-diagnostics: 3001000;reason="There has been an error authenticating the request.";category="invalid_client"

so i did a new deployed to test the azure function and i forced it to run at 8:30 am UTC(), but it raised the same error, so i did a new deployed and i set the execution time to be at 9 am UTC(), and i stopped the azure function after the deployment and i start it again.. now the call to SharePoint succeed, as follow:-

row response = StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:

so what is going on? is the reason that i need to stop/start the function after each deployment? or the azure function after certain amount of time, will fail to connect using its managed identity and will need a new deployment, and a new restart ?? Please any help on this?

Thanks

Azure Functions
Azure Functions
An Azure service that provides an event-driven serverless compute platform.
5,909 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Dasari Kamali 425 Reputation points Microsoft External Staff Moderator
    2025-05-20T15:51:25.8466667+00:00

    Hi @john john Pter,

    There has been an error authenticating the request.";category="invalid_client

    The error mainly occurs due to the client ID or client secret you are using is invalid or expired.

    When your Azure Function gets a token to access SharePoint, it stores that token to avoid asking Azure AD for a new one every time. But after you update or redeploy the function, the stored token can become outdated or invalid. Because of that, SharePoint rejects requests using this old token with a 401 Unauthorized error.

    Restarting the function clears the cached token, forcing it to request a fresh, valid token, which makes everything work again.

    To avoid issues with cached tokens, restart your Azure Function after each deployment to clear them.

    Alternatively, you can add retry logic in your code to request a fresh token if the current one fails. If possible, use a force refresh option when requesting tokens to ensure you’re not using any cached credentials.

    Below is the sample retry logic.

    int maxRetries = 3;
    for (int i = 0; i < maxRetries; i++)
    {
        try
        {
            string accessToken = await GetJwtTokenUsingSystemManagedIdentity(ignoreCache: i > 0);
            break; 
        }
        catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.Unauthorized)
        {
        }
    }
    

    If the answer is helpful, please click Accept Answer and kindly upvote it so that other people who faces similar issue may get benefitted from it.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.