SharePoint Online Authentication without SharePoint API

Accessing SharePoint Online with the SharePoint API is quite easy. You just have to create a SharePoint client context using the SharePoint Client assembly.

Suppose you cannot reference this SharePoint Client assembly. For example if you want to create a CRM Online Plug-In. These plug-ins live in a sandboxed environment where no external assemblies are allowed. How can you access SharePoint Online? There are several blog post about this topic, but the examples didn’t work for me (Luc Stakenborg and Wictor Wilén).

Based on these blog post, my dear colleagues Rene Brauwers and Wesley Bakker and logging in 1000 times at my demo tenant and analyzing the Fiddler logs I came to this solution.


You can view the code at GitHub.

Step 1 – Requesting a RpsContextCookie

string requiredAuthUrl = string.Format("{0}/_layouts/15/Authenticate.aspx?Source={1}", endPoint, HttpUtility.UrlDecode(endPoint));
HttpWebRequest request0 = (HttpWebRequest)WebRequest.Create(requiredAuthUrl);
request0.Accept = "*/*";
request0.Headers.Set(HttpRequestHeader.AcceptLanguage, "en-US");
request0.Headers.Set(HttpRequestHeader.AcceptEncoding, "gzip, deflate");
request0.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.3)";
request0.AllowAutoRedirect = false;
request0.CookieContainer = cookies;

var response0 = (HttpWebResponse)request0.GetResponse();

Step 2 – Send SAML request and receive Binairy Security Token.

var request1 = (HttpWebRequest)WebRequest.Create(stsEndpoint);
request1.CookieContainer = cookies;
var data = Encoding.ASCII.GetBytes(payLoadSts);

request1.Method = "POST";
request1.ContentType = "application/xml";
request1.ContentLength = data.Length;

using (var stream1 = request1.GetRequestStream())
stream1.Write(data, 0, data.Length);
// Response 1
var response1 = (HttpWebResponse)request1.GetResponse();
var responseString = new StreamReader(response1.GetResponseStream()).ReadToEnd();

// Get BinarySecurityToken
var xData = XDocument.Parse(responseString);
var namespaceManager = new XmlNamespaceManager(new NameTable());
namespaceManager.AddNamespace("S", "");
namespaceManager.AddNamespace("wst", "");
namespaceManager.AddNamespace("wsse", "");
var BinarySecurityToken = xData.XPathSelectElement("/S:Envelope/S:Body/wst:RequestSecurityTokenResponse/wst:RequestedSecurityToken/wsse:BinarySecurityToken", namespaceManager);

Step 3 – Send Security Token and receive Autehtication Cookies (rtFA & FedAuth)

var request2 = (HttpWebRequest)WebRequest.Create(signInUrl);
var data2 = Encoding.ASCII.GetBytes(BinarySecurityToken.Value);
request2.Method = "POST";
request2.Accept = "*/*";
request2.Headers.Set(HttpRequestHeader.AcceptLanguage, "en-US");
request2.ContentType = "application/x-www-form-urlencoded";
request2.UserAgent = browserUserAgent;
request2.Headers.Set(HttpRequestHeader.AcceptEncoding, "gzip, deflate");
request2.Host = browserHost;
request2.ContentLength = data2.Length;
request2.CookieContainer = cookies;
using (var stream2 = request2.GetRequestStream())
stream2.Write(data2, 0, data2.Length);

// Response 2
var response2 = (HttpWebResponse)request2.GetResponse();
var responseString2 = new StreamReader(response2.GetResponseStream()).ReadToEnd();

Step 4 – Request and receive Form Digest

string restUrl3 = string.Format("{0}/_api/contextinfo", endPoint);
var request3 = (HttpWebRequest)WebRequest.Create(restUrl3);
request3.CookieContainer = cookies;
request3.Method = "POST";
request3.ContentLength = 0;

// Response 3
string formDigest = string.Empty;
using (var response3 = (HttpWebResponse)request3.GetResponse())
using (var reader = new StreamReader(response3.GetResponseStream()))
var result = reader.ReadToEnd();
// parse the ContextInfo response
var resultXml = XDocument.Parse(result);
// get the form digest value
var x = from y in resultXml.Descendants()
where y.Name == XName.Get("FormDigestValue", "")
select y;
formDigest = x.First().Value;

Step 5 – Action : Create a Site!

string restUrl4 = string.Format("{0}/_api/web/webinfos/add", endPoint);
var request4 = (HttpWebRequest)WebRequest.Create(restUrl4);
request4.CookieContainer = cookies;
request4.Method = "POST";
request4.Accept = "application/json; odata=verbose";
request4.ContentType = "application/json;odata=verbose";
request4.Headers.Add("X-RequestDigest", formDigest);
string json4 = " {'parameters': { " +
"'__metadata': {'type': 'SP.WebInfoCreationInformation' }, " +
"'Url': 'RestSubWeb', " +
"'Title': 'RestSubWeb', " +
"'Description': 'REST created web', " +
"'Language':1033, " +
"'WebTemplate':'sts', " +
"'UseUniquePermissions':false} } ";
var data4 = Encoding.ASCII.GetBytes(json4);
request4.ContentLength = data4.Length;
using (var stream4 = request4.GetRequestStream())
stream4.Write(data4, 0, data4.Length);

// Response 4
var response4 = (HttpWebResponse)request4.GetResponse();
var responseString4 = new StreamReader(response4.GetResponseStream()).ReadToEnd();

6 thoughts on “SharePoint Online Authentication without SharePoint API

  1. Duncan Hepple February 19, 2015 / 10:41 am

    Hi there,

    I’m struggling with getting this working with ADFS as the IP-STS, as we use federated identities. Whenever I send a SAML request token I just get a response containing an X509 certificate and not a binary security token.

    Also, this is the first time that I’ve seen the RpsContextCookie being required for login – is this a new requirement?



  2. erwinkoens February 24, 2015 / 10:46 am

    Hi Duncan, don’t know if the RpsContextCookie is a new requirement, but it works for me. If I didn’t get that cookie the authentication fails. Do you write the same headers? That was also a challenge that I had. Please e-mail me if you do not succeed.

    Cheers, Erwin

  3. Diogo Xavier Luís December 2, 2015 / 8:51 am

    Hi there,

    I’m using this approach to authenticate against SharePoint Online OData, as I’m having trouble with it when the authentication is a hybrid setup.

    How do you define “extStsTemplate.xml”?

      • Diogo Xavier Luís December 2, 2015 / 10:38 am

        Thank you so much for the speedy reply. I ended up getting the same file via fiddler too 🙂 But it’s nice to get a confirmation.
        Can you give me examples of all your parameters (ie endPoint, requestUrl, stsEndpoint, signInUrl and browserHost).

        I’m still getting 403 on request3, and I’m not sure what I’m doing wrong 😦

      • SiobhanB (@SiobhanBaynes) July 6, 2016 / 3:26 pm

        Thanks for this, nice code. It works fine for me without the RpsContextCookie though, I can remove lines 40-52 quite happily.
        For anyone else reading this, these were my config entries:

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s