Scenario
I have a SharePoint site collection which has multiple authentication schemes (say Windows NTLM, Azure AD, Okta, ADFS or any other 3rd party Identity provider) on same URL. Now when I try to connect to that site using CSOM, I will get below 403 forbidden error from SharePoint:
The remote server returned an error: (403) Forbidden.
at System.Net.HttpWebRequest.GetResponse()
at Microsoft.SharePoint.Client.SPWebRequestExecutor.Execute()
at Microsoft.SharePoint.Client.ClientContext.GetFormDigestInfoPrivate()
at Microsoft.SharePoint.Client.ClientContext.EnsureFormDigest()
at Microsoft.SharePoint.Client.ClientContext.ExecuteQuery()
Resolution:
A simple resolution is to force the request to use Windows authentication. This works well for scenarios where you want to run a tool for provisioning or do some house keeping stuff for SharePoint.
In order to force CSOM to use windows authentication you need to add below header into all requests.
“X-FORMS_BASED_AUTH_ACCEPTED” : “f”
Here value f, denotes windows auth.
Below is a sample code on how to configure this for a sample csom console application.
Create a new Class called “WindowsClientContext” which inherits CSOM ClientContext class.
Register a web request event handler for the ClientContext, and in this handler add the above request header.
class WindowsClientContext : ClientContext
{
public WindowsClientContext(string webUrl) : base(webUrl)
{
this.ExecutingWebRequest += new EventHandler<WebRequestEventArgs>(AddWindowsAuthRequestHeader); // register a
}
private void AddWindowsAuthRequestHeader(object sender, WebRequestEventArgs e)
{
try
{
if (!e.WebRequestExecutor.RequestHeaders.AllKeys.Contains("X-FORMS_BASED_AUTH_ACCEPTED"))
e.WebRequestExecutor.RequestHeaders.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f"); // f to denote that use windows auth
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
}
}
Now in your solution use WindowsClientContext instead of ClientContext.
using (var context = new WindowsClientContext(url))
{
try
{
Web web = context.Web;
context.Load(web);
context.ExecuteQuery();
Console.WriteLine(web.Title);
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
Console.WriteLine(exception.StackTrace);
}
}
References:
Known issue if you are using PnP : PnP clones ClientContext Object for few operations and this cloning process does not clone any web request handler attached to it.


Leave a comment