This post is a contribution from Sohail Sayed, an engineer with the SharePoint Developer Support team
SharePoint Online Authentication in Powershell for CSOM when Legacy Authentication is disabled for tenant or Multi Factor Authentication is enabled for user
Authentication using SharePointOnlineCredentials class will work only if Legacy auth is enabled. If you tenant administrator has disabled Legacy Auth then SharePointOnlineCredentials will not be able to perform authentication. This also fails if the user account has Multi Factor authentication enabled. In this scenario you will be required to use Modern Authentication which uses OAuth. In powershell most SharePoint Online commandlets will be able to handle this scenario since Connect-SPOService command is able to handle this scenario. However if you authenticate successfully using Connect-SPOService command you cannot make CSOM class as we don’t get a Credentials object back from Connect-SPOService that can be used with the CSOM ClientContext class. You can work around this scenario using the OfficeDevPnP.Core.AuthenticationManager class. More details follow below.
Checking if Legacy Auth is disabled
- To check if legacy auth is disabled open SharePoint Online Management Shell.
- Run the command “Connect-SPOService -Url https://<tenant>-admin.sharepoint.com”. Replace the <tenant> with your tenant name.
- Enter credentials if prompted to authenticate.
- Run the command “Get-SPOTenant”.
- Check the property “LegacyAuthProtocolsEnabled”. If this is set to true then Legacy Authentication is enabled else disabled.
It could be possible that this is setting is set to true but Legacy Authentication is blocked via conditional access policies set by your tenant administrator. If conditional access policies are configured to block Legacy Authentication then you would be able to see an appropriate message in the network / fiddler trace for the endpoint https://login.microsoftonline.com/rst2.srf.
Below is an example of the response you will see in fiddler
<S:Fault> <S:Code> <S:Value>S:Sender</S:Value> <S:Subcode> <S:Value>wst:FailedAuthentication</S:Value> </S:Subcode> </S:Code> <S:Reason> <S:Text xml:lang="en-US">Authentication Failure</S:Text> </S:Reason> <S:Detail> <psf:error xmlns:psf="http://schemas.microsoft.com/Passport/SoapServices/SOAPFault"> <psf:value>0x80048823</psf:value><psf:internalerror> <psf:code>0x80048823</psf:code> <psf:text>AADSTS53003: Blocked by conditional access.</psf:text> </psf:internalerror></psf:error> </S:Detail> </S:Fault>
Alternatively, Legacy Authentication is enabled and there are no Conditional access policies blocking the authentication but the SharePointOnlineCredentials still fails. This would be most likely due to Multi Factor Authentication on that user account. This can be easily verified by performing a login with that user account to the SharePoint site in the browser preferably an In-Private browsing session.
Using the OfficeDevPnP.Core.AuthenticationManager to authenticate.
We need to download specific versions of assemblies for using the OfficeDevPnP.Core.AuthenticationManager class. You can get these from the Nuget package site.
- download https://www.nuget.org/packages/Microsoft.SharePointOnline.CSOM/16.1.7723.1200 or higher version.
- download https://www.nuget.org/packages/Microsoft.IdentityModel.Clients.ActiveDirectory/2.29.0
- download https://www.nuget.org/packages/SharePointPnPCoreOnline/2.26.1805.1
Note once you go to the nuget url you will find the “Manual Download” link on the right.
Download the file and rename to .zip extension.
Extract the contents on the zip files. We will be referencing this in the Powershell script.
The dlls can be found in /lib/net45 sub folder.
Code Example
Below is the code sample demonstrating using the OfficeDevPnP.Core.AuthenticationManager class for authentication.
import-module microsoft.online.sharepoint.powershell #download https://www.nuget.org/packages/Microsoft.SharePointOnline.CSOM/16.1.7723.1200 [System.Reflection.Assembly]::LoadFile("C:\TEMP\microsoft.sharepointonline.csom.16.1.7723.1200\lib\net45\Microsoft.SharePoint.Client.dll") [System.Reflection.Assembly]::LoadFile("C:\TEMP\microsoft.sharepointonline.csom.16.1.7723.1200\lib\net45\Microsoft.SharePoint.Client.Runtime.dll") [System.Reflection.Assembly]::LoadFile("C:\TEMP\microsoft.sharepointonline.csom.16.1.7723.1200\lib\net45\Microsoft.SharePoint.Client.Taxonomy.dll") #download https://www.nuget.org/packages/Microsoft.IdentityModel.Clients.ActiveDirectory/2.29.0 [System.Reflection.Assembly]::LoadFile("C:\TEMP\microsoft.identitymodel.clients.activedirectory\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll") #download https://www.nuget.org/packages/SharePointPnPCoreOnline/2.26.1805.1 [System.Reflection.Assembly]::LoadFile("C:\TEMP\sharepointpnpcoreonline.2.26.1805.1\lib\net45\OfficeDevPnP.Core.dll") $adminUrl = "https://<<tenant>>-admin.sharepoint.com" $siteUrl=https://<<tenant>>.sharepoint.com Connect-SPOService -Url $adminUrl $authManager = new-object OfficeDevPnP.Core.AuthenticationManager; $clientContext = $authManager.GetWebLoginClientContext($siteUrl); #testing CSOM calls $clientContext.Load($clientContext.Web) $clientContext.ExecuteQuery(); Write-Host $clientContext.Web.Title
You can see that we are using Connect-SPOService command first. This will cause the authentication prompt and allow the user to successfully authenticate even if the legacy auth is disabled or multi factor auth enabled. We then call $authManager.GetWebLoginClientContext($siteUrl);. This return back a ClientContext object that uses the same credentials allowing the CSOM calls to authenticate successfully now.
Note that user will need to enter credential every time the powershell script executes in a new PowerShell console session. This approach is not feasible if you have a PowerShell script executing in background without user interaction like a scheduled task. In that case you need to use app only authentication approach using Client id and client secret.