Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Connect-PnPOnline AccessToken The remote server returned an error: (401) Unauthorized. #305

Closed
TalismanM opened this issue Feb 19, 2021 · 4 comments

Comments

@TalismanM
Copy link

Reporting an Issue

When I run the Get-PnPSite command, I get the error
Get-PnPSite : The remote server returned an error: (401) Unauthorized.

Expected behavior

Get-PnPSite command result

Actual behavior

image

Steps to reproduce behavior

Script:

# Application (client) ID, tenant ID and secret
$clientId = "<Azure App ID>"
$tenantId = "<Tenant ID>"
$clientSecret = '<secret>'

# Construct URI
$uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"

# Construct Body
$body = @{
    client_id     = $clientId
    scope         = "https://graph.microsoft.com/.default"
    client_secret = $clientSecret
    grant_type    = "client_credentials"
}

$tokenRequest = Invoke-WebRequest -Method Post -Uri $uri -ContentType "application/x-www-form-urlencoded" -Body $body -UseBasicParsing
$token = ($tokenRequest.Content | ConvertFrom-Json).access_token

Connect-PnPOnline -Url "<MySite URL>" -AccessToken $token
Get-PnPSite

What is the version of the Cmdlet module you are running?

(you can retrieve this by executing Get-Module -Name "PnP.PowerShell" -ListAvailable)
image

Which operating system/environment are you running PnP PowerShell on?

  • [*] Windows
@TalismanM TalismanM added the bug Something isn't working label Feb 19, 2021
@LeonArmston
Copy link
Contributor

LeonArmston commented Feb 19, 2021

Hi

Can you please run Get-PnPException immediately after the error and include the output here.

You also dont really need to do the pure graph PowerShell and can instead use Client Secret and Client id using legacy ACS authentication to connect to your SP site.

Connect-PnPOnline -Url "https://contoso.sharepoint.com" -ClientId $clientid -ClientSecret $clientSecret

Thanks

@erwinvanhunen erwinvanhunen removed the bug Something isn't working label Feb 19, 2021
@erwinvanhunen
Copy link
Member

You're acquiring a token for the graph, however Get-PnPSite uses CSOM towards your tenant. E.g. the permission scope you acquire uses the wrong audience. Use https://[yourtenant].sharepoint.com/ instead. However, acquiring an access token using a client secret will not allow you to access SharePoint through CSOM. That's a limitation the server imposes, we cannot change that unfortunately. E.g. if you want to use app only access to SharePoint you are required to acquire a token using a certificate.

If you use the example that Leon described, then keep in mind you're falling back to the 'legacy' ACS authentication which requires to you first register an app using /_layouts/15/appregnew.aspx and then on the tenant administration site call /_layouts/15/appinv.aspx. That method will not allow you to access any Graph APIs either (which are used by PnP Cmdlets like Get-PnPTeamsTeam, the Microsoft365Group cmdlets and a few more).

The best way forward is to register your own Azure AD app with a certificate and use that:

Register-PnPAzureADApp -ApplicationName [appname] -Tenant [yourtenant].onmicrosoft.com -DeviceLogin

This will talk you to the flow of registering an app in your Azure AD tenant and it will generate two files: [appname].cer and [appname.pfx] that it will store in the current folder where you execute the app. After successfully registering you can do:

Connect-PnPOnline -Url [url] -ClientId [appid] -CertificatePath [appname.pfx] -Tenant [yourtenant].onmicrosoft.com

PnP PowerShell will then behind the scenes automatically handle all the token retrieval / caching and also will automatically refresh the token the moment it expires.

If you want to use your existing application, instead of creating a new one using Register-PnPAzureADApp, make sure that you granted that application access to SharePoints (like Sites.FullControl.All) in Azure AD. The moment you did that you can generate a self signed certificate:

$cert = New-PnPAzureCertificate -OutPfx mycert.pfx -OutCert mycert.cer
$cert

Navigate to the existing app registration in your Azure AD and upload the certificate to the app. From that moment on you can authenticate using the Connect-PnPOnline example I wrote earlier with the ClientId and CertificatePath parameters. Alternatively you use the Base64 version of the certificate that is outputted by the New-PnPAzureCertificate cmdlet:

$base64 = $cert.PfxBase64
Connect-PnPOnline -Url [url] -ClientId [clientid] -CertificateBase64Encoded $base64 -Tenant [tenant].onmicrosoft.com

@erwinvanhunen
Copy link
Member

erwinvanhunen commented Feb 19, 2021

Adding to my story above: in general, try to avoid retrieving access tokens yourself. It will lock your script in a specific scenario that can be complex to change, given the various azure ad login endpoints, different cloud instances, etc. PnP PowerShell does all the complex work for you behind the scenes (like acquiring a new token if a cmdlet wants to access the graph but the current audience is SharePoint and vice versa) as long as you provide a valid client/appid and certificate.

If you require the access token for non PnP PowerShell tasks in your script, you can use Get-PnPAccessToken to retrieve the current token. Notice that the token can expire, so retrieve the token at the moment you need it (if it's a long running script).

If you use the PnP PowerShell access token functionality, as long as the token did not expire, it will return it from an in memory cache, so no calls to Azure AD will be made. Only if the token expires the refresh token will be used to automatically retrieve a new valid access token.

@TalismanM
Copy link
Author

thanks for answers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants