When creating a lot of different web front-ends, it is always rather complex to get started with single sign-on or integrated login.

The simple way to not maintain a credential database or passwords is to validate against a 3. party website.
This is where the Office 365 Portal comes in handy, especially because many companies are already validating against or with it.

I created this code as part of another solution, the example here has been cut down for demonstration purposes and easy integration.
You will be able to validate against Portal.microsoftonline.com as long as the login is allowed for any given user.

It's easy to add, so after first login we can assign each user to roles/groups or whatever we need.
Specific domains or usernames can of course be enforced.

Login page:

simple login page

If login failed:

And our simple success login page

<?php
	require "common.php";
  //	define("DEBUG",TRUE);
  //	function log_message($message){
  //		if (DEBUG) {
  //			echo $message . "<br>";
  //		}
  //	}

  // check if sign in form was submitted
	if(empty($_POST["login"]) || empty($_POST["password"])){
	  // display login page if no submit made
		require_once("login.html");
		die();
	}
   // remove cookie file
	@unlink("tmp/cookie.txt");
	
	// Used for debugging
	//$login = "username@domain.tld";	
	//$password = "password";

	$login = $_POST["login"];	
	$password = $_POST["password"];


  // Making first GET request to the MS site.
  // This request provides us cookies + some security token are assigned
  // These tokens we use for future requests to the Office 365 Portal

	$base_url = "https://login.microsoftonline.com";
	$url = "https://login.microsoftonline.com/";

	$last_redirect_url = "";
	$content = get_page_content($url,"","","http://www.google.com/",$last_redirect_url,$error);
	if($content === FALSE){
		die('Error occured. '.$error);
	}
	file_put_contents("page1.html",$content);
  // The first GET reqeust completed. Reading all security tokens ...

	echo "Done1<br>";
	echo "Last url:$last_redirect_url<br>";
	
	$res = preg_match('|"sCtx":"([^"]+)"|',$content,$matches);
	if($res !== 1) {
		die('No ctx found');
	}
	$ctx = $matches[1];
	echo "CTX found<br>";

	$res = preg_match('|"apiCanary":"([^"]+)"|',$content,$matches);
	if($res !== 1) {
		die('No apiCanary found');
	}
	$apiCanary = $matches[1];
	echo "apiCanary found<br>";

	$res = preg_match('|client-request-id=([^"]+)"|',$content,$matches);
	if($res !== 1) {
		die('No client-request-id found');
	}
	$requestID = $matches[1];
	echo "Request-ID found<br>";

	$res = preg_match('|"hpgact":([^,]+),|',$content,$matches);
	if($res !== 1) {
		die('No hpgact found');
	}
	$hpgact = $matches[1];
	echo "hpgact found<br>";

	$res = preg_match('|"hpgid":([^,]+),|',$content,$matches);
	if($res !== 1) {
		die('No hpgid found');
	}
	$hpgid = $matches[1];
	echo "hpgid found<br>";

	$res = preg_match('|"sFT":"([^,]+)"|',$content,$matches);
	if($res !== 1) {
		die('No float token found');
	}
	$flowToken = $matches[1];
	echo "Flow token found<br>";

	$res = preg_match('|"canary":"([^,]+)"|',$content,$matches);
	if($res !== 1) {
		die('No canary found');
	}
	$canary = $matches[1];
	echo "canary found<br>";

	$useragent = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36";	
	
	$referer = $last_redirect_url;

	// The next line forms POST content to be submitted on the second request
  // In this request we emulate login to the Office 365 portal
	$payload = '{"username":"'.$login.'","isOtherIdpSupported":true,"checkPhones":false,"isRemoteNGCSupported":false,"isCookieBannerShown":false,"isFidoSupported":false,"originalRequest":"'.$ctx.'"}';

	$url = "https://login.microsoftonline.com/common/GetCredentialType";
	// We use the security tokens we have already obtained to set up correct header
	$custom_headers = array(
		'canary: '.$apiCanary,
		'client-request-id: '.$requestID,
		'hpgact: '.$hpgact,
		'hpgid: '.$hpgid,
		'Origin: https://login.microsoftonline.com',
		'X-Compress:null');

	$content = get_page_content($url,$payload,$custom_headers,$referer,$last_redirect_url,$error);
	if($content === FALSE){
		die('Error occured. '.$error);
	}
	file_put_contents("page2.html",$content);
	if(strpos($content, '"Username":"') !== FALSE && strpos($content, '"HasPassword":true') !== FALSE){
		echo "Done2(login success)<br>";
	}

	$referer = $last_redirect_url;
	$url = "https://login.microsoftonline.com/common/login";
	$custom_headers = array(		
		'Origin: https://login.microsoftonline.com',
		'X-Compress:null');
  // Finally, we are preparing form parameters to submit the third request.
  // This last POST request emulates sending password to the Office 365 Portal
  // We put already obtained security tokens into corresponding form elements
	$form = array(
		"i13" => 0,
		"login" => $login,
		"loginfmt" => $login,
		"type" => 11,
		"LoginOptions" =>3,
		"lrt" => "",
		"lrtPartition" => "",
		"hisRegion" => "",
		"hisScaleUnit" => "",
		"passwd" => $password,
		"ps" => 2,
		"psRNGCDefaultType" => "",
		"psRNGCEntropy" => "",
		"psRNGCSLK" => "",
		"psFidoAllowList" => "",
		"canary" => $canary,
		"ctx" => $ctx,
		"flowToken" => $flowToken,
		"PPSX" => "",
		"NewUser" => 1,
		"FoundMSAs" => "",
		"fspost" => 0,
		"i21" => 0,
		"CookieDisclosure" => 0,
		"i2" => 1,
		"i17" => "",
		"i18" => "",
		"i19" => 5972767
	);

	$content = get_page_content($url,$form,$custom_headers,$referer,$last_redirect_url,$error);
	if($content === FALSE){
		die('Error occured. '.$error);
	}
	file_put_contents("page3.html",$content);

	// On request finished we check for some needed parameters to the response
  // and decide whether sign in was successful or not
	if(strpos($content, '"urlPost":"/kmsi"') !== FALSE && strpos($content, '"sCanaryTokenName":"canary"') !== FALSE){
		$file = "success.html";
	} else {
    $file = "fail.html";
	}
	// The next 3 lines puts JS code to redirect to appropriate HTML file (success.html or fail.html)
	echo "<script>";
	echo "location.href = '".$file."'";
	echo "</script>";

	die(1);	
	// $res = preg_match('|<form id="credentials" method="post" action="([^"]+)"|',$content,$matches);
	// if($res !== 1) {
	// 	die('No form found1');
	// }
	// $post_url = $base_url.$matches[1];
	// echo "Post url : $post_url<br>";
	
	// $res = preg_match('|<input type="hidden" name="ctx".*?value="([^"]+)"|',$content,$matches);
	// if($res !== 1) {
	// 	die('No form found3');
	// }
	// $ctx = $matches[1];

	// $res = preg_match('|<input type="hidden" name="flowToken".*?value="([^"]+)"|',$content,$matches);
	// if($res !== 1) {
	// 	die('No form found4');
	// }
	// $flowToken = $matches[1];
	
	// $params = array(
	// 	"login" => $login,
	// 	"passwd" => $password,
	// 	"ctx" => $ctx,
	// 	"flowToken" => $flowToken,
	// 	"persist" => "0",
	// 	"n1"=>"-1410021990000",
	// 	"n2"=>"-1410021990000",
	// 	"n3"=>"-1410021990000",
	// 	"n4"=>"96673",
	// 	"n5"=>"96673",
	// 	"n6"=>"96781",
	// 	"n7"=>"96781",
	// 	"n8"=>"NaN",
	// 	"n9"=>"96934",
	// 	"n10"=>"96934",
	// 	"n11"=>"97091",
	// 	"n12"=>"97091",
	// 	"n13"=>"97092",
	// 	"n14"=>"97096",
	// 	"n15"=>"20",
	// 	"n16"=>"97489",
	// 	"n17"=>"97490",
	// 	"n18"=>"97498",
	// 	"n19"=>"158",
	// 	"n20"=>"1",
	// 	"n21"=>"1",
	// 	"n22"=>"1152",
	// 	"n23"=>"1",
	// 	"n24"=>"18",
	// 	"n25"=>"0",
	// 	"n26"=>"0",
	// 	"n27"=>"0",
	// 	"n28"=>"0",
	// 	"n29"=>"-1410022087463",
	// 	"n30"=>"-1410022087463",
	// 	"n31"=>"0",
	// 	"n32"=>"0",
	// 	"n33"=>"0",
	// 	"n34"=>"0",
	// 	"n35"=>"0",
	// 	"n36"=>"0",
	// 	"n37"=>"0",
	// 	"n38"=>"0",
	// 	"n39"=>"0",
	// 	"n40"=>"1410022087499",
	// 	"n41"=>"1410022087507",
	// 	"n42"=>"1410022087485",
	// 	"n43"=>"1410022087499",
	// 	"type"=>"11",
	// 	"LoginOptions"=>"3",
	// 	"NewUser"=>"1",
	// 	"idsbho"=>"1",
	// 	"PwdPad"=>"",
	// 	"sso"=>"",
	// 	"vv"=>"",
	// 	"uiver"=>"1",
	// 	"i12"=>"1",
	// 	"i13"=>"MSIE",
	// 	"i14"=>"9.0",
	// 	"i15"=>"1087",
	// 	"i16"=>"800"
	// );
	// $content = get_page_content(
	// 	$post_url,$params,"https://login.microsoftonline.com/",$error);
	// if($content === FALSE){
	// 	die('Error occured. '.$error);
	// }
	// file_put_contents("page2.html",$content);

	// echo "Done2<br>";
	// if(
	// 	strpos($content,"<noscript>JavaScript required to sign in</noscript><title>Continue</title>") !== FALSE
	// 	&&
	// 	strpos($content,"<body onload=\"javascript:DoSubmit();\">") !== FALSE)
	// {
	// 	echo "LOGIN OK!";
	// } else {
	// 	echo "LOGIN FAILS!";
	// }

NOTE: Keep in mind, You must move the tmp location or create a folder called tmp with RW permissions.

Download the source files:

Download “Office365SecurityToken.zip” Office365SecurityToken.zip – Downloaded 247 times – 5 KB