Creating a SharePoint CSOM ClientContext with an authentication cookie

There are a few ways to use CSOM to authenticate to SharePoint. Some of those include:

- Using an AccessToken (OAuth2/SP2013 app model)
- With the SharePointOnlineCredential helper class where you supply a username and password

Now, I wanted to do neither of these things. In my case, I had already logged into SharePoint, and had a FedAuth and rtFa cookie available to me and wanted to construct a ClientContext from those. It took me a while to work out – skip to the end for the code :-)

Wictor Wilen did some work in this area a few years back with his MsOnlineClaimsHelper class. I tried to follow his methods to form my ClientContext by using a CookieContainer to add the FedAuth cookie to ClientContext WebRequest objects, and applying a UserAgent header, and so on…but was consistently met with a 403 response from SharePoint.

Then I came across a post comparing MsOnlineClaimsHelper with the SharePointOnlineCredentials class – which helpfully pointed out that the latter was a supported replacement and should be used. The SharePointOnlineCredential class makes CSOM really trivial to use with a username and password:

SecureString pw = new SecureString();
foreach (char c in "mypassword".ToCharArray())
pw.AppendChar(c);
context.Credentials = new SharePointOnlineCredentials("jonathan.cardy@repstor.com", pw);
context.Load(context.Web);
context.ExecuteQuery();

The crucial point is that at some point along the line, the SharePointOnlineCredentials class converts a username and password into a FedAuth cookie, and it’s the process of supplying the FedAuth cookie in ClientContext web requests that I was having trouble implementing myself. So at this point I opened up the JetBrains dotPeek decompiler for the Microsoft.SharePoint.Client.Runtime.dll assembly, and found the SharePointOnlineAuthenticationModule which did exactly that, in the GetSpoAuthCookieAndUpdateRequest method:

private bool GetSpoAuthCookieAndUpdateRequest(WebRequest request, SharePointOnlineCredentials spoCredentials, bool preAuthentication)
{
string uriString = request.RequestUri.ToString();
int length1 = uriString.IndexOf('?');
if (length1 > 0)
uriString = uriString.Substring(0, length1);
int length2 = uriString.IndexOf('#');
if (length2 > 0)
uriString = uriString.Substring(0, length2);
int length3 = uriString.IndexOf("/_vti_bin", StringComparison.OrdinalIgnoreCase);
if (length3 > 0)
uriString = uriString.Substring(0, length3);
int length4 = uriString.IndexOf("/_api", StringComparison.OrdinalIgnoreCase);
if (length4 > 0)
uriString = uriString.Substring(0, length4);
Uri url = new Uri(uriString);
string authenticationCookie;
if (preAuthentication)
{
authenticationCookie = spoCredentials.GetAuthenticationCookie(url, false, true);
if (string.IsNullOrEmpty(authenticationCookie))
authenticationCookie = spoCredentials.GetAuthenticationCookie(url, true, true);
}
else
authenticationCookie = spoCredentials.GetAuthenticationCookie(url, true, true);
if (string.IsNullOrEmpty(authenticationCookie))
return false;
request.Headers[HttpRequestHeader.Cookie] = authenticationCookie;
return true;
}

The important bit here is just the single line:
request.Headers[HttpRequestHeader.Cookie] = authenticationCookie;

Previously I had tried to set the cookies via a CookieContainer object, which didn’t work (I got 403 errors). I don’t know why, but setting the cookie directly via the Cookie header works.

Now in our case we have both a FedAuth and an rtFa cookie so we can put it all together like this:

ClientContext cc = new ClientContext(spSiteUrl);
cc.ExecutingWebRequest += (object sender, WebRequestEventArgs e) =>
{
    e.WebRequestExecutor.WebRequest.Headers[HttpRequestHeader.Cookie] = "FedAuth=" + _fedAuth + ";rtFa=" + _rtFa;
};

By trial and error I found that naming the cookie FedAuth and not SPOIDCRL – as it’s named in the SharePointOnlineCredential code – was required. Also, without passing the rtFa cookie, I got 403 errors.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>