How to log into Office365 or SharePoint Online using PHP

My previous post on adding items to a SharePoint list was using a normal SharePoint server. I have had a few question on how to do the same thing for the Office 365 and SharePoint Online since the previous code did not work. With the help of this website I was able to create some code on getting the proper authentication cookies to use for interacting withOffice 365 and SharePoint Online. The following code will get the two authentication cookies, FedAuth and rtFa which need to be passed for each request.


$username = 'user@name.onmicrosoft.com';
$password = 'password';
$host = "https://yourdomain.sharepoint.com";

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

/**
 * 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();
    curl_setopt($ch,CURLOPT_URL,$url);
    curl_setopt($ch,CURLOPT_POST,1);
    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);      
    
    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
    <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>
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);
    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);
}

37 thoughts on “How to log into Office365 or SharePoint Online using PHP

  1. hi wes, I was once able to get the token but most of the time Sharepoint online is giving back this error:

    PasswordNotMatch0

    Any idea why?

  2. What’s the right way to use the data stored in the array $authCookies ?
    I’ve tryied to “setcookie” (both cookies) after “parsing” each array element string but it didn’t work.

    Thankyou.

  3. Hi wes…this is a great article, thank you so much. I tested and works great. But we need a little bit more…this is only to get the cookies but I don’t know how to use it…could you post a complete example to connect and get list item from Office365? I think everybody will appreciate this because there is not working example on Internet.
    Thanks in advance!

      1. I know this is an old post, but I’m searching for help on this and found your blog in the search. I’d be willing to provide an Office 365 account for you to play with to code this out.

  4. Hi Wes,

    Thank you very much for this interesting post!
    I was able to get the security token and the header, but when comparing $loop[0] to ‘Set-Cookie’ goes wrong. What are your purposes here? $authCookies is always empty for me..

    Can you give me a deeper explanation on this?

    Thank you in advance!
    Alex Sanchez

    1. Alex, I process the header info to extract the information I need. Check the $header variable to make sure your getting a response.

      1. Thanks for your reply Wes,

        I had imcompatible ssl versions. Adding: curl_setopt($ch,CURLOPT_SSLVERSION,3); solved that for me!

        Do you have any idea how to send the gathered cookies in a request. Cant find documentations on this?

        Thanks in advance.

  5. Hello,

    Is want to use the script above to directly connect to a teamsite or admin-page of Office365

    I changed the relevant variables but I always get stuck on the login-page…

    Can anyone please help me?

    tyvm

    $username = ‘myname@mydomain.onmicrosoft.com’;
    $password = ‘mypassword’;
    $host = “https://portal.microsoftonline.com”;

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

    header(“Location: https://portal.microsoftonline.com“);
    exit;

    1. Dennis, if you print out $authCookies do you have values? If so, then you have to keep those values and pass them to each call you do to the site.

  6. Hi Wes, thanks for this script, I require to make one app capable of login with Office365 account and your approach give me a way to go since I was a little confused with Azure SSO and others terms and services I read about.

    About the script I have two commens:
    – For this to work you have to let cURL connect to the URL, quick and dirt way (befofe curl_execute): curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    – The exception when $result is false wasn’t caught, it should look like:
    // catch error
    try{
    if($result === false) {
    throw new Exception(‘Curl error: ‘ . curl_error($ch));
    }
    } catch(Exception $e) {
    echo ‘Excepcion capturada: ‘, $e->getMessage(), “\n”;
    }

    Thanks for this post

  7. Thank you very much friend!!! I added this code to my site successfully. Now my site is interconnected with office 365.

    1. Dear Anton,
      Could you please help me to be connected to our Sharepoint online team site after getting the two cookies?
      I do not know how to use the two cookies via php to echo a listname from our Sharepoint team site.
      Many Thanks in advance.

  8. Hi,

    I try to connect my website with office 365 with modifiyng this script.

    The problem is i don’t get the token, $token is always null. I think i missing something.

    Does someone has a script to connect office 365 ?

    Thanks you !!!

  9. I’ve got the tokens but they are used to send additional requests to the web service without authentication. The big question is…how do we use the same cookies to forward the client into the services without them having to login yet again??

  10. Thanks for the great post. Connecting to Office 365 is working well. I am trying to migrate data from Google Drive to SkyDrive Pro and would like to impersonate each Office 365 user rather than asking them to supply their credentials. After hours of Googling I have been unable to find out how to do this using curl. Are you have to point be in the right direction?

  11. Dear Sir,
    Could you please help me to be connected to our Sharepoint online team site after getting the two cookies?
    I do not know how to use the two cookies via php to echo a listname from our Sharepoint team site.
    Many Thanks in advance.

    1. To get data from office 365 you need to query a web service (List available at http://msdn.microsoft.com/en-us/library/hh147180.aspx). To do so i use nusoap. Example:
      function getWebService($url, $endpoint, $webService, $params, $querySharepoint) {
      $authCookies=$this->getCookies();
      require_once(dirname(__FILE__).’/nusoap-0.9.5/nusoap.php’);

      // echo $url;
      // echo “\n”;
      // flush();

      $client = new nusoap_client($this->translate_uri($url).’?WSDL’, ‘wsdl’);
      $client->soap_defencoding = ‘UTF-8’;
      $client->decode_utf8 = false;
      $client->setCookie(‘rtFa’, $authCookies[0]);
      $client->setCookie(‘FedAuth’, $authCookies[1]);
      $client->setCurlOption(CURLOPT_SSL_VERIFYPEER, false);
      $client->setCurlOption(CURLOPT_SSLVERSION, 3);
      $client->setEndpoint($this->translate_uri($endpoint));
      $client->querySharepoint=$querySharepoint;
      $client->call($webService, $params, ”, ”, ”, true);

      // echo ‘Request

      ' . htmlspecialchars($client->request, ENT_QUOTES) . '

      ‘;
      // echo ‘Response

      ' . htmlspecialchars($client->response, ENT_QUOTES) . '

      ‘;
      // echo ‘Debug

      ' . htmlspecialchars($client->debug_str, ENT_QUOTES) . '

      ‘;

      return $this->parseResponseToXml($client->response);
      }
      Where $url and $endpoint are urls of the webservice https://…………./_vti_bin/xxxxx.asmx?WSDL, $webService its the name of the service itself and $params are the params needed for the web service to be consulted. $querySharepoint its a modification i have done to the library nusoap to get additional info that needs a complex explanation.

  12. Is it possible to use the values retrieved here to then store the cookies in the users browser and redirect a user to a relevant Sharepoint page? Something specific rather than the main page of a site — achieving a form of single sign on w/o a federated service. In this case it’d help me run a kiosk application w/o sign-in.

    Thanks!
    Nick

    1. You cannot find it where? in the response? what is your response of getAuthCookies($token, $host) function?

  13. 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 at the begining of the getSecurityTokenXml function. Would be something like this:
    $username=str_replace(array(”, ‘&’, ‘”‘, “‘”), array(‘<‘, ‘>’, ‘&’, ‘"’, ‘'’), $username);
    $password=str_replace(array(”, ‘&’, ‘”‘, “‘”), array(‘<‘, ‘>’, ‘&’, ‘"’, ‘'’), $password);
    Good info of the web services to use once logged:
    http://msdn.microsoft.com/en-us/library/hh147180.aspx
    Good info on retrieving user data from office 365 once logged:
    http://www.vrdmn.com/2013/07/sharepoint-2013-get-userprofile.html

Leave a comment