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 Reply