Code sample 3:

Below is example code for authenticating using low-level PHP, but it is recommended to use a standardard PHP library for doing this, especially for handling caching.


$setup = [
  'certPath' => 'somefile.pfx', // Full path to certificate .pfx file
  'certPwd' => 'some-password', // Password of .pfx file, must be protected.
  'client_id' => 'some-guid', // Provided by EG, in the form of a GUID
  'tenant' => 'https://login.microsoftonline.com/mytenant.onmicrosoft.com',  // Provided by EG, in the form of https://login.microsoftonline.com/mytenant.onmicrosoft.com
  'service_resource_id' => 'some-other-guid' // Can be found on our main documentation page for each service/environment
];

openssl_pkcs12_read(file_get_contents($setup["certPath"]), $certs, $setup["certPwd"]);
$cert = openssl_x509_read($certs["cert"]);
$x5t = base64urlencode(openssl_x509_fingerprint($cert, 'sha1', true));
$pkey = openssl_pkey_get_private ($certs["pkey"]);
$exp = time() + (60 * 10); // Token is only needed to get the access_token, can expire it right away, but set to 10 minutes to avoid clock drift issues.
$nbf = time() - (60 * 10); // 10 minutes in the past
$client_id = $setup['client_id'];
$subject = $client_id;
$jti = guidv4();
$token_endpoint = $setup['tenant'].'/oauth2/token';

// Optional: It is recommended to use a standard PHP-library to create JWT
$header = '{"alg":"RS256","typ":"JWT","x5t":"' . $x5t .'"}';
$payload = '{
  "aud": "'.$token_endpoint.'",
  "exp": '.$exp.',
  "iss": "'.$client_id.'",
  "jti": "'.$jti.'",
  "nbf": '.$nbf.',  
  "sub": "'.$subject.'"
}';
$unsigned_token = base64_encode($header).".".base64_encode($payload);
openssl_sign($unsigned_token, $signature, $pkey, 'SHA256');
$token = $unsigned_token.".".base64urlencode($signature);

echo "Using certificate: ". openssl_x509_parse( $cert )["name"]."\n"; // Optional: Print/Check expiry of client certificate
echo "AAD token endpoint: " . $token_endpoint."\n";
$post = [
    'resource' => $setup['service_resource_id'],
    'client_id' => $client_id,
    'client_assertion' => $token,
	'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
	'grant_type' => 'client_credentials',
];
if(substr( $token_endpoint, 0, 8 ) !== "https://") { throw new Exception("https required in token endpoint url"); }
$ch = curl_init($token_endpoint);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
curl_setopt($ch, CURLOPT_VERBOSE, false);

// Note: Do not do this if you already have an access_token that has not yet expired, you should re-use it.
$response = curl_exec($ch);
$httpcode = curl_getinfo($ch,CURLINFO_HTTP_CODE);
curl_close($ch);
$response_json = json_decode($response);
$expires_on = $response_json->expires_on; // Unix time
$access_token = $response_json->access_token;
echo "Response code: ".$httpcode.". Access token expires at ".date('Y-m-d H:i:s', $expires_on)."\n";

// Todo: Send the request to the service you want, passing the header: "Authorization: Bearer $access_token"

function base64urlencode($value) {
    return rtrim(strtr(base64_encode($value), '+/', '-_'), '=');
}

function guidv4()
{
    if (function_exists('com_create_guid') === true)
        return trim(com_create_guid(), '{}');

    $data = openssl_random_pseudo_bytes(16);
    $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100
    $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10
    return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}