azure-active-directorypermissionsaccess-tokensharepoint-onlinepnp.powershell

Access and Modify SharePoint Online list using PnP.Powershell and AccessTokens / Registered App


With Microsoft's changes away from user/password authentication, I'm trying to update a script to use a registered app but having trouble accessing the SharePoint Online list and getting a 401 Unauthorized error even though I've followed everything I've found online, so I'm turning to the community for help. 🙂

This is my test code:

Import-Module MSAL.PS
Import-Module PnP.PowerShell 

$TenantId = "REDACTED"
$siteUrl = "REDACTED"
$listName = "People Who Are In"
$Scope = "https://graph.microsoft.com/.default"

# Clear-MsalTokenCache
$Client = Get-PnPStoredCredential -Name IntranetAzureApp
$authResult = Get-MsalToken -TenantId $tenantId -ClientId $client.UserName -ClientSecret $client.Password -Scopes $scope 
$AccessToken = $authResult.AccessToken

Connect-PnPOnline $siteUrl -AccessToken $AccessToken

Get-PnPList -Identity $listName

When I run it, I get the following error:

Line |
  26 |  Get-PnPList -Identity "People Who Are In"
     |  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | The remote server returned an error: (401)
     | Unauthorized.

I've tried a whole handful of things but nothing seems to be working. I figure the issue is likely permissions however I've tried every API permission I could think of. With the code and result above, the API Permissions are set to Sites.FullControl.All, however I've also tried, Sites.Manage.All, Sites.ReadWrite.All, and Sites.Selected (and the followed the process to give read/write permission to the site via a POST request). Both via Microsoft Graph and Sharepoint.

I've also read some places that the scope should be the Sharepoint, however I get the same 401 error when setting the scope to https://REDACTED.sharepoint.com/.default, and get the error:

AADSTS500011: The resource principal named https://REDACTED.sharepoint.com/sites/Intranet 
was not found in the tenant named REDACTED This can happen if the application has not been 
installed by the administrator of the tenant or consented to by any user in the tenant. 
You might have sent your authentication request to the wrong tenant.

I've looked at trying to do this through the Microsoft.Online.Sharepoint.Powershell module, however that doesn't seem to support the use of AccessTokens and I need the script to run unattended.

I've also tried running this in PostMan hitting the endpoint for https://graph.microsoft.com/v1.0/sites/{{IntranetSiteId}}/lists/{{PWAI List ID}} and that + /items and was able to get a proper 200 response with data, which tells me the issue may not be one of permissions since the raw GET requests are succeeding.

I've also confirmed in jwt.ms that my token does in fact contain the roles needed.

"roles": ["Sites.FullControl.All"],

Any insight into what may be going on or what I may be missing would be greatly appreciated.


Solution

  • The error "The remote server returned an error: (401) Unauthorized" usually occurs if the access token is not valid or do not have required permissions to perform the action.

    Note that: To fetch the lists using PnP PowerShell, you need to fetch the access token using SharePoint scope not Microsoft Graph API scope.

    Hence, Grant Sites.FullControl.All SharePoint API permission to the Microsoft Entra ID application:

    enter image description here

    Upload the .cer certificate in the Certificates & secrets blade:

    enter image description here

    Modify the script to generate access token via Certificate:

    $TenantId = "TenantID"
    $ClientId = "ClientID"
    $siteUrl = "https://YourTenant.sharepoint.com/sites/testrukk"
    $listName = "ruklist"
    $Scope = "https://YourTenant.sharepoint.com/.default"
    
    # Replace with your certificate thumbprint and path to the private key if needed
    $certThumbprint = "ThumbPrintFromAbove"
    $cert = Get-Item "Cert:\CurrentUser\My\$certThumbprint"
    
    # Authenticate using the certificate
    $authResult = Get-MsalToken -TenantId $TenantId -ClientId $ClientId -ClientCertificate $cert -Scopes $Scope
    $AccessToken = $authResult.AccessToken
    
    # Connect to the SharePoint site
    Connect-PnPOnline $siteUrl -AccessToken $AccessToken
    
    # Retrieve the list
    $list = Get-PnPList -Identity $listName
    

    enter image description here

    Decoded token:

    enter image description here

    If still the issue persists, then Navigate to https://TenantDomain.sharepoint.com/sites/SiteName/_layouts/15/appinv.aspx . Pass the ClientID and give access by using the XML request. Refer this SO Thread by me.

    <AppPermissionRequests AllowAppOnlyPolicy="true">
        <AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="FullControl" />
    </AppPermissionRequests>
    

    And to create the .cer and .pfx certificates Refer this MsDoc

    Reference:

    [] Connect-PnPOnline AccessToken The remote server returned an error: (401) Unauthorized. · Issue #305 · pnp/powershell · GitHub by erwinvanhunen