Remote authentication in SharePoint Online

Suppose you want to programmatically access SharePoint Online from Node.js, Ruby, Java, [insert your favorite platform here],…. SharePoint offers data access APIs, but how do you authenticate? SharePoint Online uses claims based authentication. Documentation about programmatic authentication is fairly limited and restricted to .NET solutions.

Fortunately there is this great post from Wictor Wilén, providing a working .NET example that connects to SharePoint Online. It requires the SharePoint Client Object Model and Windows Identity Foundation SDK and Runtime (WIF) to run.

OK, but can we use a platform other than .NET? In the end it’s all just data and http under the hood…

Fiddler to the rescue! By running the sample application and using Fiddler to look at the http traffic under the hood, we can find out how the authentication sequence works.

It’s actually quite simple:

image

Step 1: Send SAML Request to STS

The application POSTs an SAML Request Security Token message to the Microsoft Online Security Token Service (STS), located at the following address:

https://login.microsoftonline.com/extSTS.srf

The Request Security Token message should contain username, password of a Microsoft Live account and the url of your SPO site. Here is a template that you can use to build the XML message.

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
      xmlns:a="http://www.w3.org/2005/08/addressing" 
      xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
  <s:Header>
    <a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action>
    <a:ReplyTo>
      <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
    </a:ReplyTo>
    <a:To s:mustUnderstand="1">https://login.microsoftonline.com/extSTS.srf</a:To>
    <o:Security s:mustUnderstand="1" 
       xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <o:UsernameToken>
        <o:Username>[username]</o:Username>
        <o:Password>[password]</o:Password>
      </o:UsernameToken>
    </o:Security>
  </s:Header>
  <s:Body>
    <t:RequestSecurityToken xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
      <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
        <a:EndpointReference>
          <a:Address>[endpoint]</a:Address>
        </a:EndpointReference>
      </wsp:AppliesTo>
      <t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType>
      <t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>
      <t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType>
    </t:RequestSecurityToken>
  </s:Body>
</s:Envelope>

 

Step 2: Receive SAML Response

If the credentials are valid, the STS will respond with a Request Security Token Response message. Look for the BinarySecurityToken tag and you’ll find the Security Token:

.....
<wst:RequestedSecurityToken>
   <wsse:BinarySecurityToken Id="Compact0">t=EwBgAk6hB...
   </wsse:BinarySecurityToken>
</wst:RequestedSecurityToken>
.....

Extract the token value (including ‘t=’) for the next step.

Step 3: Send the Security Token to SharePoint Online

After you received the Security Token from STS, you need to POST the Security token to SPO:

http(s)://yourdomain.sharepoint.com/_forms/default.aspx?wa=wsignin1.0

E-accounts need to include a user-agent header. Your POST should look something like this:

POST http://yourdomain.sharepoint.com/_forms/default.aspx?wa=wsignin1.0 HTTP/1.1
Host: yourdomain.sharepoint.com
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Content-Length: [calculate]

t=EwBgAk6hB....abbreviated

Step 4: Receive the authentication cookies

After SPO has validated the Security Token, it will return 2 authentication cookies in the HTTP header: FedAuth and rtFa.

.....
Set-Cookie: rtFa=0U1zw+TnLmLfDtzmppbu....abbreviated
Set-Cookie: FedAuth=77u/PD94bW.....abbreviated
.....

Extract the values of both cookies.

Step 5: Send requests including authentication cookies

For each subsequent request from your application to SPO, you must include the FedAuth and rtFa cookie in your request headers. Like this:

....
Cookie: FedAuth=77u/PD....LzwvU1A+; rtFA=0U1zw+TnL......AAAA==
....

This will satisfy SPO to process your request, whether it is a request for a page, a document, a web service or ListData service.

And that’s all there is to it!

I hope this is useful for others implementing SharePoint Online access. If you want more details, please check out my SharePoint client for Node.js which includes authentication code in JavaScript.

Thanks for reading.

Advertisement

78 thoughts on “Remote authentication in SharePoint Online

    • Hi,

      Thanks!

      No, it won’t work the same. FBA probably works a little bit different. But using the same approach, just by looking with an http tracer like Fiddler, you will be able to figure out the sequence. I think you will need to POST the credentials to the authentication receiver, which will pass session tokens to you when credentials are valid.

      • HI Istak,

        Thank you very much for you responce. My programming knowldge is limited to writting a “Hello World” app, so if I provide you with the fidler capture could you help?

  1. Hi Luc,
    I appreciate your write up of this solution. The response I get from the STS differs from your example. The wst:RequestedSecurityToken node has an EncryptedData node in it instead of a wsse:BinarySecurityToken node. It looks like this:

    gqyVo+lKFt6iKaoMzLR1schvcGE=

    microsoftonline.com

    [redacted]

    [redacted]

    Any thoughts? Thanks so much.

    rory

    • Hi Rory,

      Couple of questions:
      – are you login in to SharePoint Online or an on-premiss SharePoint?
      – do you have a P or an E account?
      – are you using a Microsoft online account or federated account (using your own AD)?

      • Thanks for your reply.
        It is SharePoint online. I’m using the URL above as the STS.
        It is a P1 account.
        It is a Microsoft online account.

        Thanks for your assistance.

      • Rory, Istak, thanks for discussing the EncryptedData tag being returned for those sites that were migrated from BPOS to 365. Office365 says this problem is not supported; the community recommends recreating the migrated sites under new 365 sites. This BPOS/365 problem, like a few other problems, goes away.

        In troubleshooting this we at least learned the role of the EndpointReference tag and how it works with our individual sites. We’re working with AS3 in both desktop and browser client.

        Thanks again

      • Hi,

        I have this exact behavior but with an office365 P account created in 2013, January. So it is not only related to a BPOS/o365 migration.
        Domain name is customized. I need to change the appliesTo Endpoint to “portal.microsoftonline.com” otherwise I got a “The partner DNS used in the login request cannot be found” error.
        But then, the response token is not in the expected form.

        Any ideas ?

  2. Hi Luc! It is a really great article. I am testing it in my browser console. How should enpoint address look like? “http://example.sharepoint.com” ?

      • For some reason I get responseText: “”, statusText: “error”, even the status is 200 OK. In Firefox I get the hardcoded SAML: $.get("file:///C:/test/saml.xml", {}, function(data) { foo = data; }, "text") Then I pass post it to the login page: jQuery.post("https://login.microsoftonline.com/extSTS.srf", foo, function(data) {t = data;console.log(data); }) In saml username is like “user@example.onmicrosoft.com” and endpoint is “http://example.sharepoint.com”. Do you see what can be wrong?

      • I think you will bump into the following limitations, trying to use the extSTS.srf service from a browser:
        – The browser will follow automatically redirects (302)
        – Browser will not allow cross-domain XHR posts (due to Same Origin Policy)
        – The cookies sent by the STS are flagged as HTTPOnly. This means XHR cannot get to them.

        The authentication sequence described is really targeted at remote authentication by server apps, e.g. based on Node, Java, PHP etc.

  3. Playing around with this the other day led to an interesting discovery. Apparently the two cookies do not have to be associated with the sharepoint.com top domain to be validated. Part of my duties at work is development, and since my boss loves pitching Office 365 to our clients, that includes a lot of Sharepoint Online development.That being said, I now have about 6 or 7 different MSOnline accounts to juggle through as I work on different projects.

    I realized, however, that you can maintain multiple Sharepoint Online logins to different sites simultaneously by doing the following:

    Using the authorization method described above, acquire the authentication cookie to all the different Sharepoint Online subdomains that you need to be logged into.

    Modify the cookie you so that the domain is yoursite.sharepoint.com instead of the standard sharepoint.com.

    Using the IESetProtectedModeCookie api call from the ieframe.dll, set the two modified cookies in Internet Explorer. (I also used InternetSetCookieEx just to be safe)

    Without going to the login portal, open a tab directly to the yourdomain.sharepoint.com site. You should be logged in already.

    Couple of notes:

    If you have an existing authorization cookie with the sharepoint.com domain, you’ll need to delete it before trying this. If you don’t, it will throw an error when you attempt to go to any site other than the one linked to the sharepoint.com domain. (This is because Internet Explorer is sending two sets of authorization cookies, and Sharepoint Online doesn’t know what the hell is going on)

    This will only work for browsing and working with the Sharepoint site. As far as I know, none of the functionality will work with any of the other Office 365 services. I’d even suggest avoiding going to portal.microsoftonline.com for a bit, as that may screw with the cookies you set.

    Not sure if this does anything to any existing connections you may have in Outlook, etc to your Exchange server. I haven’t had much time to play with it since.

    I haven’t had a chance to write an application leveraging this hack – only wrote up a quick proof of concept to test my theory. Seems like a cool little hack that should be able to save me some time, though.

    Just thought I’d share.

  4. Hi Isak,

    Thanks for the post. I am trying to replicate it in C#. I get the token from sts fine but I get a 403 error when I try and post it to https://mydomain.sharepoint.com/_forms/default.aspx?wa=wsignin1.0

    This comes back as part of the header

    {SPRequestGuid: 88c3db96-2a1c-441e-94fa-49ec7ce18b90
    X-SharePointHealthScore: 0
    X-Forms_Based_Auth_Required: https://mydomain.sharepoint.com/_forms/default.aspx?ReturnUrl=/_layouts/Error.aspx
    X-Forms_Based_Auth_Return_Url: https://mydomain.sharepoint.com/_layouts/Error.aspx
    X-MSDAVEXT_Error: 917656; Access denied. Before opening files in this location, you must first browse to the web site and select the option to login automatically.
    MicrosoftSharePointTeamServices: 14.0.0.6109
    Content-Length: 13
    Content-Type: text/html; charset=utf-8
    Date: Tue, 01 May 2012 19:43:20 GMT
    P3P: CP=”ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo PSA PSD TAI TELo OUR SAMo CNT COM INT NAV ONL PHY PRE PUR UNI”
    Server: Microsoft-IIS/7.5
    X-Powered-By: ASP.NET

    }

    Any ideas what could be causing this?

    Thanks again!

    • Hi,

      If you have an E account (you’re using https), you may need to include a user agent http header in your request. Try for example:
      User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)

      Let me know if this helps.

      • Hi Luc,

        Thanks for you reply.

        I did indeed have to send the user agent. I skimmed over that line in Wictor Wilén’s tutorial you posted above.

        SPO is sending back the HTML page for the logged in SP home page now, just have to pass the response to the client and I think i’ll have a remote login working!

        Thanks for this post, it really helped. I’ll let you know how it works if you want? But I think it’s just some C# fiddling.

        Thank again!

        Daniel

      • Hi Daniel,

        Thanks for your response. Please let me know your findings and I will update the article.

        Best regards,

        Luc

      • You need to set the request object’s AllowAutoRedirect to false, (HttpWebRequest.AllowAutoRedirect) to prevent the login page being returned in the response.

  5. Hi Luc,
    This post is very good. I’m trying to do this by posting a SAML 1.1 token obtained from a federated ADFS 2.0 server but I get a response stating “WebSSO invalid assertion”. Do you have a sample of doing that? my outgoing soap request is the same as yours, but I replaced the o:Username element with an o:Embedded element, containing the xml saml token returned from ADFS (an Assertion element)

    Thanks!

  6. Dear Istak,

    I loved this artile, you have saved lot of my time. This is simply superb.

    I am working on Sharepoint Online Connector. I am doing this in Java. I have followed your approach and succeeded partially.

    I am able to get the token but when I am trying to get the cookie I am getting 403 error code. Please take a look at my code and suggest me to solve this issue.

    private static String sendTokenRequest(String tokenString) {
    String myStatusMsg = null;

    try {
    // Opens service URL as an Http connection
    HttpURLConnection myURLConnection =
    (HttpURLConnection) new URL(“https://tatasharepointonline.sharepoint.com/_forms/default.aspx?wa=wsignin1.0”).openConnection();

    // Prepares connection with xml content type
    myURLConnection.setRequestMethod(“POST”);
    myURLConnection.setRequestProperty(“Content-Type”, “application/x-www-form-urlencoded”);
    myURLConnection.setRequestProperty(“User-Agent”, “Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)”);

    myURLConnection.setDoOutput(true);
    myURLConnection.setDoInput(true);

    myURLConnection.getOutputStream().write(tokenString.getBytes());

    // Reads response message
    BufferedReader myReader = new BufferedReader(new InputStreamReader(myURLConnection.getInputStream()));
    StringBuilder myResponseText = new StringBuilder();
    String myLine = null;
    while ((myLine = myReader.readLine()) != null) {
    myResponseText.append(myLine);
    }
    myReader.close();

    System.out.println(“myResponseText: ” + myResponseText);
    } catch (Throwable e) {
    System.out.println(e.getMessage());
    myStatusMsg = e.getMessage();
    }

    return myStatusMsg;
    }

    Output:
    myURLConnection.getResponseCode(): 403
    Server returned HTTP response code: 403 for URL: https://tatasharepointonline.sharepoint.com/


    Token value:
    t=EwBwAk6hBwAUIQT64YiMbkZQLHdw6peopUrQ0O8AAVJ1XTXOLhoFQvTzXQSI6D5eOeXD2gt5otWknzWANHzmNWf76Vc8Vm0fw/Ct3243xC9ukmawKgh6h9EVoJn+SyXutyTQ6DcdBV+ShbzjzOfcH7uX5ywVaOP/sajvb2PzVbq+gw05T3+43IRybylHkvVHnogH3NFV9fx1LkKZm6nbc8gAoypHJqZtAahYvpYQ1k01YhTpGTz5XK4EdfWtA3W5dvvAgNimwOBHtuTBKknKbK7fk9IX6MPnvW6hqGi7YCKiZfXCG7GlzGKGm/BCGFqQuDye2Prj3XnkGOnAYl+eaTtIQcqtQdBn08BYZ0IBiLpvpu9JRUMVT57nq3ANcRMDZgAACKCHA8D/EJ/hQAFL+ko/kOgwpcFTNjY5Dg6sIK98/nchRXkxC6nzZuHw5Vbigv0SDaEn7LNMG66Kp35lQoQNOu4/hhEID6YjbMenYsaMTHROr7B8mNEQs0RfAxBQv2rKOZLWT6gACfmrPjjiuLt4PwoH1wuu3Ymu/U7xul27Eaep0xIKq0kpHACp8AwP7+oaSnX1j/AsJTjd9mP6nHEIaGwCajYHXzLsg9Ks0Y6A02HaSuiwDK6SKWH7p4SCl4peYQWXf8UWb5l8ldXhTwGH1AOOoNPG+YO2XCsMLZ5hJSa6dKlHi+V933HKmp+68lYGklZS8yjMvF5w8DHCpmRk5tY1JcRy7sF62NCwmSawTDMAccfp728SSwKe6CmREnh0cWBF4ybgn12Q3G6biufkV8B1C1YMAu062MvsSkV0xGY/8Lwt4NQKVYoOWagB&p=

    • Hi,

      Thanks!

      The error seems to indicate that SPO doesn’t accept your authentication request. Suggestions: Check the outgoing request for correct Host and Content-Length headers with an HTTP tracer like Fiddler. Verify that the tokenstring is sent correctly (no additional encoding).

      • Thanks. I have used Wireshark tool for tracking.

        I have one question here…I am writing the binary token string to request output stream (no extra encoding). Is it correct approach?
        The Java code looks like this,
        ———–
        Writer writer = new OutputStreamWriter(myURLConnection.getOutputStream());
        writer.write(tokenString);
        writer.flush();
        writer.close();
        ———–

        My header looks likes this,
        ——————————–
        Hypertext Transfer Protocol

        POST /_forms/default.aspx?wa=wsignin1.0 HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): POST /_forms/default.aspx?wa=wsignin1.0 HTTP/1.1\r\n

        Request Method: POST
        Request URI: _forms/default.aspx?wa=wsignin1.0
        Request Version: HTTP/1.1

        Content-Type: application/x-www-form-urlencoded\r\n
        User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)\r\n
        Host: tatasharepointonline.sharepoint.com\r\n
        Accept: text/html, image/gif, image/jpeg, *; q=2, */*; q=.2\r\n
        Connection: keep-alive\r\n

        Content-Length: 841\r\n
        [Content length: 841]
        \r\n
        [Full request URI: http://tatasharepointonline.sharepoint.com/_forms/default.aspx?wa=wsignin1.0%5D
        Line-based text data: application/x-www-form-urlencoded
        [truncated] t=EwBwAk6hBwAUIQT64YiMbkZQLHdw6peopUrQ0O8AAeXNlWrcxefOraVTYRkdFd1vPcBtOXH6A3xGeq6xkSEmpdbT+Gzfn4+MgmxriN4shzKACrg56EuBE0cwQAaAQRSdsRBRXSRjGpU50xNS9+4MB6r2XBqFE235tERxcIFOR3QNcE8zdmkfyruP2bt4shJjwP13XMGJElzwYKy3S01CmZO6MAXji1pVmJz+e0HUCkmhURGfxIFbw3k4okI9lDwEf0guXPFveHu8/ALhTPKKNSzedh/FCN5Y3NZxH2NBjqzt7LAvsw3FOedmlF2JvaCY/QdsSHYJKxoDRoddfY3e98oj4ANDJ9dZJo5EP6vqlIBN8EZkigMJz0ZbLbbpfDADZgAACE0vkvu9JcAyQAHGz+X8WMvhY5+4gax2zDgTp17DKaLyt2jeKov3h2+tJFoT+lSAL81L1X2iILe6cDKjS/bXNm2WOOlZJAqo0JF90AyE5XPnlFs8H7W0hhednJgbZ+kG1CXrAkT1RlDwL1J6yJz5dZ8ATKd4AqqxatJickzBt/IC+ZsKY+59d+tRDn0lxeOC9YQK5a4e65UkFEdfDNsAcKOA67XJM6ITNQ2GoXg5gnSD1/ekDGIg1OzM9J579dbCBeb2B/ZYKqaDmx144OgO5t4r/qcBMh4cl6CpDhHOllM0UryvZCi3TU1e45tCQj7iZbggR0vxVLe+baVFYCXJuvk79uj72Y+swoXIQvxdUPhETLoiRkOtEY5YUHElhLgGFh05DAHKYg0+S8pWKTqyQNIuul27kwxJjFVdKpMHLKYWj0Z3IpAcp4TDiKgB&p=

      • Hi Istak,

        Finally I made it worked.

        The issue is with auto redirect. We need to set allow auto redirect as false.
        Java code

        To get the cookie with the token string, here is sample code in Java
        =====================================================
        HttpURLConnection myURLConnection1 = (HttpURLConnection) new URL(“https://tatasharepointonline.sharepoint.com/_forms/default.aspx?wa=wsignin1.0”).openConnection();

        myURLConnection1.setRequestMethod(“POST”);
        myURLConnection1.setRequestProperty(“User-Agent”, “Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)”);
        myURLConnection1.setRequestProperty(“Content-Type”, “application/x-www-form-urlencoded”);
        myURLConnection1.setRequestProperty(“Content-Length”, utf8TokenStringBytes.length + “”);
        myURLConnection1.setFollowRedirects(false);
        System.out.println(utf8TokenStringBytes.length);
        myURLConnection1.setDoOutput(true);
        myURLConnection1.setDoInput(true);
        myURLConnection1.getOutputStream().write(tokenString.getBytes());
        myURLConnection1.getOutputStream().close();

        List cookies = myURLConnection2.getHeaderFields().get(“Set-Cookie”);

        for(String str:cookies) {
        System.out.println(str);
        }

  7. My Sharepoint online account domain is “tatasharepointonline.sharepoint.com”

    When I am sending SAML request to microsoft Online STS, I am giving end point as “https://tatasharepointonline.sharepoint.com”. Is this correct?

  8. Hi Istak,
    Nice post,
    I have a dashboard section on my home page of the sharepoint site, which brings data from a sensitive list. Currently users who dont have access to the list cant see anything in the Dashboard section.
    Is there any method by which i can use a default system account and display this data to all the users, without giving them direct access to the list.

    Please suggest.

    • You could have a in-between server that logs in with an account that has full access to the sensitive list and provide the aggreated data for display in the dashboard in the user’s browser

      • yes,
        I m making use of an Ajax call, and passing a ‘Beforesend’ as header for authentication, still getting access denied when tested for users who dont have direct acess,

        $.ajax({
        crossDomain:true,
        xhrFields: {
        withCredentials: true
        },

        beforeSend : function(req, settings) {
        req.setRequestHeader(‘Authorization’, make_base_auth(‘USERNAME’,’PASSWORD in HEX’));
        },
        url: sSiteUrl1 + sCmdParameters1,
        type: “GET”,
        dataType: “xml”,
        data: “”,
        success: function (){
        alert(‘Success’);
        },
        error: function (xhr, message, error) {

        alert(error);

        },
        complete: processRequest,
        contentType: “text/xml; charset=\”utf-8\””
        });

        });

        Is there a better methods ?

  9. Hello lstak
    I was wondering if you have some sample code for uploading attachments (like pdfs) to list-elements in SharePoint Online. I’m stuck with this.
    I’m finishing a simple implementation in Java to upload files in a SharePoint Online. I’ve already finished Claims Based Authentication but when It comes to upload a file to a List Element I got stuck.

  10. Hi Istak,

    Wonderful article and it save a hell of a time for me.

    I have a quick question. If I have a sharepoint site (S), having subsites (SS1 & SS2) and that user A & user B have no access to site S, but have access to site SS1 & SS2 respectively, what should be my endpoint look like? will that still follow the general convention

    http(s)://yourdomain.sharepoint.com/_forms/default.aspx?wa=wsignin1.0

    or it will look like

    http(s)://yourdomain.sharepoint.com/SS1/_forms/default.aspx?wa=wsignin1.0
    http(s)://yourdomain.sharepoint.com/SS2/_forms/default.aspx?wa=wsignin1.0

    I received 404 (File not found) exception while adding SS1/SS2 to the URL.

    Thanks once again for a wonderful information so far.

    Naval.

    • Hi Naval,

      I am glad it is useful.

      The endpoint in the Token Request (see template) should at a minimum contain the domain name.

      You should submit the received token to http(s)://yourdomain.sharepoint.com/_forms/default.aspx?wa=wsignin1.0 to get the authentication cookies.
      Basically this step is to provide you with session cookies, but not your authorization.

      Once you have the cookies, your client can request specific pages/docs inside sites or subsites. SharePoint will either grant or refuse those request based on authorization settings in SharePoint.

      I hope this helps!

      • Hi Istak,

        Yeah that helps me to be complete.

        Thanks once again !!!

        Cheers,
        Naval.

      • Hey Istak,

        I have one more question to you.

        For a given user “user@somedomain.com” , is there a way to identify the sharepoint online URL(s) programmatically?

        Regards,
        Naval.

      • Hi Istak,

        Let us say that I have a username naval.patel@mycompany.net

        When i login on http://www.office365.com, i enter my credentials & password and then i am presented a web page with following 3 options to work with:

        1. Outlook
        2. Lync
        3. Team Site (This is our Sharepoint Online link)

        Is there a programmatic way to obtain this Sharepoint online link?

        Regards,
        Naval.

  11. Pingback: How to log into Office365 or SharePoint Online using PHP « Come get your GEEK on!

  12. Hi,
    I am just looking for a way in my app to auto discover the SPO online url for the user instead of letting him to provide the SPO url.

    Regards,
    Venkat.

  13. Hello,

    Currently we are able to access Sharepoint 2007/2010 Objects (Lists/Libraries)using axis 1.4 generated code (JAX-RPC) in Java.

    Now we want to connect and access Objects from Sharepoint Online.
    1) The first step towards it is to connect to SPO which we did successfully using Claims-Based-Authentication and have the Authentication CookiedToken.
    2) Now, how do we use this Authentication Cookie to access Objects (Lists) from SPO in our axis generated code ?

    Below is a code snippet we use to access List :
    public void getListCollection()
    {

    ListsSoapStub mListsService;
    ListsLocator locator = new ListsLocator();
    mListsService = (ListsSoapStub)locator.getListsSoap(_listsServiceURL);
    mListsService.setUsername(_username);
    mListsService.setPassword(_password);
    GetListCollectionResponseGetListCollectionResult listsResult = mListsService.getListCollection();


    }
    public com.microsoft.schemas.sharepoint.soap.GetListCollectionResponseGetListCollectionResult getListCollection() throws java.rmi.RemoteException
    {
    if (super.cachedEndpoint == null) {
    throw new org.apache.axis.NoEndPointException();
    }
    org.apache.axis.client.Call _call = createCall();
    _call.setOperation(_operations[6]);
    _call.setUseSOAPAction(true);
    _call.setSOAPActionURI(“http://schemas.microsoft.com/sharepoint/soap/GetListCollection”);
    _call.setProperty(org.apache.axis.client.Call.SEND_TYPE_ATTR, Boolean.FALSE);
    _call.setProperty(org.apache.axis.AxisEngine.PROP_DOMULTIREFS, Boolean.FALSE);
    _call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOAP11_CONSTANTS);
    _call.setOperationName(new javax.xml.namespace.QName(“http://schemas.microsoft.com/sharepoint/soap/”, “GetListCollection”));

    setRequestHeaders(_call);
    setAttachments(_call);

    java.lang.Object _resp = _call.invoke(new java.lang.Object[] {});
    }

    Any help would be appreciated.
    Thanks in advance.

    • Hi Kiran,

      Sorry for late reply.

      You should set the authentication cookies on the subsequent Axis client request. Based on some googling, I believe this can be done like this:

      _call.setProperty(org.apache.axis.transport.http.HTTPConstants.HEADER_COOKIE2, “FedAuth=77u/PD….LzwvU1A+; rtFA=0U1zw+TnL……AAAA==”);

      Good luck,

      Luc

      • Hello,

        Can you please let me know How to get list of all the Sites on Sharepoint online server.

        As we can get list of all the “Lists/Libraries” using getListCollection() if ListSoap as below :

        ListsSoap mListService = _mSharePointSession.GetListsService();
        GetListCollectionResult result = mListService.getListCollection();

        Then how can I get list of all the “sites” using SitesSoap?

        Thanks.

  14. Goedemiddag Luc,

    Is het mogelijk om op basis van het bovenstaande na de authenticatie (Settings van de benodigde cookies) ook andere pagina’s binnen de Office 365 dashboard op te vragen? Ik zou graag namelijk op basis van screen scraping techniek gegevens van een bepaalde pagina uit willen lezen.

    Alvast bedankt voor je antwoord!

    • Hi, ik denk wel dat dat zou kunnen, maar heb het nooit zelf uitgeprobeerd. Kijk eens met Fiddler naar het http verkeer als je ongeauthenticeerd naar zo’n Office 365 authenticatie pagina gaat. Dan kun je zien of vergeljkbaar proces gevolgd wordt.

  15. Dag Luc,

    Ik wil via php automatisch kunnen inloggen op SPO en/of Office365 dmv credentials die ik wil linken aan gebruikers in een drupal site.

    volgend script heb ik online gevonden:
    http://macfoo.wordpress.com/2012/06/23/how-to-log-into-office365-or-sharepoint-online-using-php/

    het lukt me om een security token te ontvangen maar niet om de 2 cookies vervolgens terug te krijgen

    online is er niet zoveel documentatie hierover terug te vinden.

    ik ben nog niet zo heel lang bezig met het coderen in php… ik hoop dat jij me wil/kan helpen?

    alvast erg bedankt!

    Groeten Dennis

    <?php

    $username = 'myname@mydomain.onmicrosoft.com';
    $password = 'mypassword';
    $host = "https://mydomain.sharepoint.com&quot;;

    $token = getSecurityToken($username, $password, $host);
    //printf($token);
    $authCookies = getAuthCookies($token, $host);

    print('

    ');
    printf($token);
    print('

    ‘);

    print(‘

    ');
    print_r($authCookies);
    print('

    ‘);

    /**
    * Get the FedAuth and rtFa cookies
    *
    * @param string $token
    * @param string $host
    * @return array
    * @throws Exception
    */
    function getAuthCookies($token, $host) {

    $url = $host . “/_forms/default.aspx?wa=wsignin1.0”;

    $ch = curl_init();
    print(‘

    ');
        print_r($ch);
        print('

    ‘);
    //curl_setopt($ch,CURLOPT_SSLVERSION,3);
    curl_setopt($ch, CURLOPT_URL,$url);
    curl_setopt($ch, CURLOPT_POST,true);
    curl_setopt($ch, CURLOPT_POSTFIELDS,$token);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    // curl_setopt($ch,CURLOPT_VERBOSE, 1); // For testing
    curl_setopt($ch, CURLOPT_HEADER, true);

    $result = curl_exec($ch);

    // catch error
    if($result === false) {
    throw new Exception(‘Curl error: ‘ . curl_error($ch));
    }

    //close connection
    curl_close($ch);

    print(‘

    ');
        print($result);
        print('

    ‘);

    return getCookieValue($result);
    }

    /**
    * Get the security token needed
    *
    * @param string $username
    * @param string $password
    * @param string $endpoint
    * @return string
    * @throws Exception
    */
    function getSecurityToken($username, $password, $endpoint) {

    $url = “https://login.microsoftonline.com/extSTS.srf”;

    $tokenXml = getSecurityTokenXml($username, $password, $endpoint);

    $ch = curl_init();
    curl_setopt($ch,CURLOPT_URL,$url);
    curl_setopt($ch,CURLOPT_POST,1);
    curl_setopt($ch,CURLOPT_POSTFIELDS,$tokenXml);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);

    // catch error
    if($result === false) {
    throw new Exception(‘Curl error: ‘ . curl_error($ch));
    }

    //close connection
    curl_close($ch);

    // Parse security token from response
    $xml = new DOMDocument();
    $xml->loadXML($result);
    $xpath = new DOMXPath($xml);
    $nodelist = $xpath->query(“//wsse:BinarySecurityToken”);
    foreach ($nodelist as $n){
    return $n->nodeValue;
    break;
    }
    }

    /**
    * Get the XML to request the security token
    *
    * @param string $username
    * @param string $password
    * @param string $endpoint
    * @return type string
    */
    function getSecurityTokenXml($username, $password, $endpoint) {
    return <<<TOKEN

    http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue

    http://www.w3.org/2005/08/addressing/anonymous

    https://login.microsoftonline.com/extSTS.srf

    $username
    $password


    $endpoint

    http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey
    http://schemas.xmlsoap.org/ws/2005/02/trust/Issue
    urn:oasis:names:tc:SAML:1.0:assertion

    TOKEN;
    }

    /**
    * Get the cookie value from the http header
    *
    * @param string $header
    * @return array
    */
    function getCookieValue($header)
    {
    $authCookies = array();
    $header_array = explode(“\r\n”,$header);
    //printf($header);
    foreach($header_array as $header) {
    $loop = explode(“:”,$header);
    if($loop[0] == ‘Set-Cookie’) {
    $authCookies[] = $loop[1];
    }
    }
    unset($authCookies[0]); // No need for first cookie
    return array_values($authCookies);
    }

    ?>

  16. Pingback: SharePoint 2013 and Windows 8 apps - better together Part 2: Platform choice, using the right API and data access - BBB - Bas Blogging 'Bout SharePoint

  17. Pingback: CRM Online to SharePoint Online Integration using REST and ADFS | MSCRM Bing'd

  18. Pingback: talking to the active STS in office online | Peter's ruminations

  19. Thanks for the great post. You’ve saved my back for the project. With the information you shared, I could implement a basic Java client for Sharepoint 2013 REST services.

    Hope I can extend it and share with the public.

  20. Anyone please let me know how do I achieve loading Sharepoint online 2010 page into C# web browser control. something like this webbrowser.navigate(“https://myonlinesite.sharepointonline.com”,null.null,hdr);

    How do i pass credentials in header and go to the post login page after successful credential validation. The Web browser control is in windows application. Thanks for the help.

  21. Hi Luk!
    This is really awesome post. Thanks for sharing.
    I would like to get a list of all to Office 365 workspaces where I have access. Also is there any way in which I can avoid inserting credentials in the code?

  22. Leveraged this information and translated to PowerShell 3.0. Thought I would share to help the bloke down the line. Here is a somewhat “crud”y example.

    #https://allthatjs.com/2012/03/28/remote-authentication-in-sharepoint-online/
    #http://rambletech.wordpress.com/2011/09/21/posting-soap-request-from-windows-powershell/

    $RequestSecurityToken=@”

    http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue

    http://www.w3.org/2005/08/addressing/anonymous

    https://login.microsoftonline.com/extSTS.srf

    NotReal@MySite.Com
    YouWish


    http://mysite.sharepoint.com

    http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey
    http://schemas.xmlsoap.org/ws/2005/02/trust/Issue
    urn:oasis:names:tc:SAML:1.0:assertion

    “@

    $authenticationURL = “https://login.microsoftonline.com/extSTS.srf”

    $SecurityToken = Invoke-WebRequest -Uri $authenticationURL -Method Post -ContentType “text/xml” -Body $RequestSecurityToken -UserAgent ([Microsoft.PowerShell.Commands.PSUserAgent]::InternetExplorer)
    $binaryToken = ([xml]$SecurityToken.Content).Envelope.Body.RequestSecurityTokenResponse.RequestedSecurityToken.BinarySecurityToken.”#text”

    $siteTokenConverter = “https://mysite.sharepoint.com/_forms/default.aspx?wa=wsignin1.0”

    $AuthenticationCookieResponse = Invoke-WebRequest -Uri $siteTokenConverter -Method Post -ContentType “text/xml” -Body $binaryToken -UserAgent ([Microsoft.PowerShell.Commands.PSUserAgent]::InternetExplorer) -SessionVariable Session

    $getInfoURI = “https://mysite.sharepoint.com/somesite/_vti_bin/listdata.svc/AList?$filter=MyVariable eq ‘Anything'”

    $data = Invoke-WebRequest -Uri $getInfoURI -WebSession $Session -UserAgent ([Microsoft.PowerShell.Commands.PSUserAgent]::InternetExplorer)

    $AddSomethingURI = “https://mysite.sharepoint.com/somesite/_vti_bin/listdata.svc/AList”

    $repsonse =Invoke-WebREquest -Uri $AddSomething -WebSession $Session -UserAgent ([Microsoft.PowerShell.Commands.PSUserAgent]::InternetExplorer)

    $newRecord = @MyVariable= “New Value”} | ConvertTo-Json

    Invoke-WebREquest -Uri $AddSomethingUri -WebSession $Session -Body $newRecord -Method Post -ContentType application/json -UserAgent ([Microsoft.PowerShell.Commands.PSUserAgent]::InternetExplorer)

  23. Thanks a lot! I was struggling with this today. The token part was straightforward but I didn’t know about the cookie part. Microsoft assumes you are using their APIs naturally and does not document this so well..

    Here is a complete python example.. hopefully it will help someone else.


    import urllib2
    import cookielib
    import urlparse
    import jinja2
    from urllib2 import HTTPCookieProcessor
    from lxml import etree
    # Setup Jinja for SAML
    JINJA_TEMPLATE_PATH = "/Users/Brian/IdeaProjects/yggdrasil/templates"
    JINJA_ENVIRONMENT = jinja2.Environment(
    loader=jinja2.FileSystemLoader(JINJA_TEMPLATE_PATH),
    extensions=['jinja2.ext.autoescape'],
    autoescape=True)
    saml_template = JINJA_ENVIRONMENT.get_template('saml.xml')
    # lxml needs namespaces
    namespaces = {'S': "http://www.w3.org/2003/05/soap-envelope&quot;,
    'wst': "http://schemas.xmlsoap.org/ws/2005/02/trust&quot;,
    'wsse': "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd&quot;,
    'wsu': "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd&quot;,
    'saml': "urn:oasis:names:tc:SAML:1.0:assertion",
    'wsp': "http://schemas.xmlsoap.org/ws/2004/09/policy&quot;,
    'psf': "http://schemas.microsoft.com/Passport/SoapServices/SOAPFault&quot;}
    # This is the external microsoft service that will handout a token when given credentials
    mso_auth_uri = "https://login.microsoftonline.com/extSTS.srf&quot;
    # Authentication front-end for SharePoint Online (hand it a token, gives us a cookie)
    spo_auth_uri = "/_forms/default.aspx?wa=wsignin1.0"
    # Change this stuff
    username = "user@mydomain.onmicrosoft.com"
    password = "p@ssword1"
    sp_site = "https://mydomain.sharepoint.com&quot;
    sp_login_uri = urlparse.urljoin(sp_site, spo_auth_uri)
    # file we want
    sp_url = "https://mydomain.sharepoint.com/_vti_bin/ListData.svc/&quot;
    # xpath for binarytoken (not valid for pre-Office 365 SPO, probably doesn't apply to you)
    tokenpath = "/S:Envelope/S:Body/wst:RequestSecurityTokenResponse/wst:RequestedSecurityToken/wsse:BinarySecurityToken"
    # populate SAML + need cookie jar to magically handout cookies.
    login_vars = {'username': username, 'password': password, 'url': sp_url}
    saml = saml_template.render(login_vars)
    jar = cookielib.CookieJar()
    opener = urllib2.build_opener(HTTPCookieProcessor(jar))
    # MSO/SPO prefers a browser UA
    opener.addheaders = [
    ('User-Agent', 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11')]
    # 1. Get the token from MSO
    f = opener.open(mso_auth_uri, saml)
    tree = etree.parse(f)
    # 2. Receive SAML response, store token
    binarytoken = tree.xpath(tokenpath, namespaces=namespaces)[0].text
    # 3. Post token to sharepoint online to get cookie
    opener.open(sp_login_uri, data=binarytoken)
    # 4/5 CookieJar will handle the cookies, request what we actually want.
    resp = opener.open(sp_url)
    # Do something interesting…
    print resp.read()


    <?xml version="1.0" encoding="UTF-8"?>
    <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <s:Header>
    <a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action>
    <a:ReplyTo>
    <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
    </a:ReplyTo>
    <a:To s:mustUnderstand="1">https://login.microsoftonline.com/extSTS.srf</a:To>
    <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
    <o:UsernameToken>
    <o:Username>{{ username }}</o:Username>
    <o:Password>{{ password }}</o:Password>
    </o:UsernameToken>
    </o:Security>
    </s:Header>
    <s:Body>
    <t:RequestSecurityToken xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
    <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
    <a:EndpointReference>
    <a:Address>{{ url }}</a:Address>
    </a:EndpointReference>
    </wsp:AppliesTo>
    <t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType>
    <t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>
    <t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType>
    </t:RequestSecurityToken>
    </s:Body>
    </s:Envelope>

    view raw

    saml.xml

    hosted with ❤ by GitHub

  24. Hi Istak:

    Thanks for sharing knowledge.
    I am new to sharepoint and can you please help me to solve my problem.
    My requirement is From java application need to setup single sign on for sharepoint 2013. Using opensaml we are generating SAML token. My idea/guess is we need to pass the generating the SAML token to sharepoint so that sharepoint validate the token and return the accesstoken for the feature calls. But I am not sure what apis I need to call and setup required in sharepoint 2013 etc.., Can you please help/guide me to achieve this.

    Thanks,
    -Praveen

  25. Great script showing how to login. I’ve been successful at logging in using this technique, and have the token value as well as fedauth and rtFa cookies available to me server side when developing this out.

    What I’d like to do though is set those cookies in the users browser and redirect them to the Sharepoint portal to a particular page. I’ve tried to set them using my usual cookie setting means, but it doesn’t seem to want to work.

    I can retrieve the token and just put it in a form and submit the form to the signin1.0 script, but that always ends me up at the root of the site instead of letting me choose specific pages to end up on.

    This is for a kiosk application, so that it can startup without having to login where a federated system wouldn’t work due to other constraints. Any ideas on how I can get the user to where they need to be?

    Thanks!

  26. Pingback: SharePoint Online | Yet Another SharePoint Blog

  27. Pingback: SharePoint Online client for PHP | Yet Another SharePoint Blog

  28. Hi, if any on you is having as response of the security token “Invalid STS request” its because either the username or the password contains invalid xml chars (, &, ” or ‘). You should replace those chars by their html entity. In php would be something like this:
    $username=str_replace(array(”, ‘&’, ‘”‘, “‘”), array(‘<‘, ‘>’, ‘&’, ‘"’, ‘'’), $username);
    $password=str_replace(array(”, ‘&’, ‘”‘, “‘”), array(‘<‘, ‘>’, ‘&’, ‘"’, ‘'’), $password);

  29. Thanks Luc. Your article helped a lot. I was stuck with a sample code that was behaving differently than browser. Browser based application was getting re-authentication redirects(302) but my sample code was getting 403 errors. That seemed to get resolved by adding the user agent header.

  30. Pingback: Authenticating with SharePoint Online in a Ionic/Angular/PhoneGap app |

  31. Hi,
    thank you very much for your tutorial! It was really helpful!
    So my application is working now with getting lists using the cookies FedAuth and rtFa (don’t need the request digest). My problem is, that I don’t know when the values of the cookies will expire and if I have to refresh them (and how).
    I found this: https://support.office.com/en-us/article/Session-timeouts-for-Office-365-37a5c116-5b07-4f70-8333-5b86fd2c3c40
    Which Office 365 service is the correct one of the authorization you described? Sharepoint Online or Azure Active Directory?
    And is there a possibility either to refresh easily my cookie values instead of doing the whole process or to set that my authentication will not expire?

Leave a Reply

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

WordPress.com Logo

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

Facebook photo

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

Connecting to %s