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.

authprocess


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();
office365auth01

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", "http://www.w3.org/2003/05/soap-envelope");
namespaceManager.AddNamespace("wst", "http://schemas.xmlsoap.org/ws/2005/02/trust");
namespaceManager.AddNamespace("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
var BinarySecurityToken = xData.XPathSelectElement("/S:Envelope/S:Body/wst:RequestSecurityTokenResponse/wst:RequestedSecurityToken/wsse:BinarySecurityToken", namespaceManager);
office365auth02

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();
office365auth03

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", "http://schemas.microsoft.com/ado/2007/08/dataservices")
select y;
formDigest = x.First().Value;
}
}
office365auth04

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();
office365auth05


9 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?

    Thanks

    Duncan

  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:

  4. Bryant November 4, 2018 / 9:09 am

    Hello, I can get Token and FedAuth and rtFa cookie .
    But I want to use those data to login my sharepoint site page(https://teaner.sharepoint.com/site/mysite)on browser.
    How to do it?
    Thank you.

  5. Jose June 23, 2021 / 3:28 pm

    Hi Duncan,

    The code builds successfully as is, but it would be nice to have a detailed explanation on how to properly configure the App.Config file, specifically for:

    SharePointOnlineEndpoint
    SharePointOnlineSTS
    SharePointOnlineSignInUri
    BrowserHost
    BrowserUserAgent

    After configuring those, is that all we need to do?

    Does the github code automatically create a new site? what if we don’t want to create a new site, all we want to do is authenticate in order to successfully use SSIS SharePoint List Adapter to download/ upload/ update sharepoint online 365 list records. At what part of the code can we start to do other actions when authentication is successful?

  6. Jose June 23, 2021 / 3:34 pm

    Hi Erwin,

    The code builds successfully as is, but it would be nice to have a detailed explanation on how to properly configure the App.Config file, specifically for:

    SharePointOnlineEndpoint
    SharePointOnlineSTS
    SharePointOnlineSignInUri
    BrowserHost
    BrowserUserAgent

    After configuring those, is that all we need to do?

    Does the github code automatically create a new site? what if we don’t want to create a new site, all we want to do is authenticate in order to successfully use SSIS SharePoint List Adapter to download/ upload/ update sharepoint online 365 list records. At what part of the code can we start to do other actions when authentication is successful?

Leave a reply to Jose Cancel reply