Simple PHP Microsoft Graph Application

While my example uses PHP, hopefully the basics can be useful to anyone else who is looking to do work with the Microsoft Graph API.

There are two portals in which you can view/edit various parts of your application. The first is the Micrsoft Application Registration portal. The second, and more useful one, is the Azure Portal. When logging into either Microsoft portal, note that your login is most likely onyen@ad.unc.edu - not something like onyen@sog.unc.edu. You can find your application under "Azure Active Directory" on the left, then click on "App Registrations."

You’ll need a few pieces of information to get started:

  1. Client ID: This is taken from the apps.dev.microsoft.com portal and is the "Application ID" listed.
  2. Client Secret: This is the key that ITS generates for you. If, for some reason, you need a new one I believe you can self-generate these in the Azure application portal.
  3. Redirect URL: This actually isn't used, but it does need to be set to a valid redirect URL for your application. You can edit these in the Azure portal under 'Reply URLs'.

Once you have those three pieces of information, you'll need to figure out what permissions you need. You can view those in the "Required Permissions" section of your application's settings on the Azure portal. Look over what's there and take note. You'll need to ask ITS to set those permissions and then authorize them if you need any application permissions.

Note that everything after the client ID is necessary, but doesn't need to be changed.

The URL to authorize the permissions for you application is: https://login.microsoftonline.com/common/adminconsent?client_id=CLIENT_ID&state=12345&redirect_uri=http://localhost
Also note that in most cases, the /common/ is replaced by our tenant (admin.live.unc.edu). In the authorization URL, however, you want to use /common/.

Finally, you'll need the object ID of whatever you want to access. In this example, we'll access my calendar so we need my object ID. This can be found in the Azure portal by clicking "Users" under "Azure Active Directory." Search for the onyen you want, and click on the user. You'll see the Object ID part way down the page. Copy that.

The actual request URL for my calendar events is a GET request to: https://graph.microsoft.com/v1.0/users//events.

The flow of a client credentials (or daemon) request is as follows:

  1. Send a request for a token using your client id and client secret
  2. Extract the token from the response
  3. Send a request for the information you want. The access token you received should be in the header of your request

composer.json

{
    "require": {
		"league/oauth2-client": "^2.0",
        "microsoft/microsoft-graph": "^1.0",
        "guzzlehttp/guzzle": "~6.0",
        "thenetworg/oauth2-azure": "^1.3"
    }
}

index.php

<style>
	h3 {
		margin-bottom: 0;
	}
 
	.event {
		margin-bottom: 3rem;
	}
 
	.dates {
		font-style: italic;
	}
 
	.location {
		font-size: .8rem;
	}
</style>
 
<?php
 
 
/*
 * https://developer.microsoft.com/en-us/graph/docs/api-reference/beta/api/user_list_calendars
 */
 
 
// Require our 3rd party libraries such as Oauth2
require_once __DIR__ . '/vendor/autoload.php';
 
// Include the Microsoft Graph classes
use Microsoft\Graph\Graph;
use Microsoft\Graph\Model;
 
// This is taken from the apps.dev.microsoft.com portal an is the "Application ID"
const CLIENT_ID     = 'this is your client ID';
 
// This is the secret ITS generates for you
const CLIENT_SECRET = 'this is your client secret';
 
// This should be one of the reply URLs set in your application
const REDIRECT_URI           = 'https://app.sog.unc.edu';
 
// This is the object id of the user we want to use
const USER = 'this is the user ID';
 
// Set up a new Oauth2 client that will be talking to Azure
$provider = new TheNetworg\OAuth2\Client\Provider\Azure([
    'clientId'                => CLIENT_ID,
    'clientSecret'            => CLIENT_SECRET,
    'redirectUri'             => REDIRECT_URI,
]);
 
// Change the URLs of our Oauth2 request to the correct endpoint and tenant
$provider->urlAPI = "https://graph.microsoft.com/v1.0/";
$provider->resource = "https://graph.microsoft.com/";
$provider->tenant = 'admin.live.unc.edu';
 
// Try to get an access token using the client credentials grant.
$accessToken = $provider->getAccessToken( 'client_credentials', $options );
 
// Start a new Guzzle client
$client = new \GuzzleHttp\Client();
 
// Set up headers
$headers = [
    'Authorization' => 'Bearer ' . $accessToken->getToken(),
];
 
// Wrap our HTTP request in a try/catch block so we can decode problems
try {
 
	// Set up our request to the API
	$response = $client->request(
		'GET',
		'https://graph.microsoft.com/v1.0/users/' . USER . '/events',
		array( 'headers' => $headers )
	);
 
	// Store the result as an object
	$result = json_decode( $response->getBody() );
 
// Decode any exceptions Guzzle throws
} catch (GuzzleHttp\Exception\ClientException $e) {
    $response = $e->getResponse();
    $responseBodyAsString = $response->getBody()->getContents();
    echo $responseBodyAsString;
    exit();
}
?>
 
<h1>Showing Calendar Events for: nmbenes@sog.unc.edu</h1>
 
<?php foreach( $result->value as $event ): ?>
	<div class="event">	
		<h3><?php echo $event->subject; ?></h3>
 
		<?php if( $event->isAllDay ): ?>
			<div class="dates">
				<?php
					$start = new DateTime( $event->start->dateTime );
					$start->setTimezone( new DateTimeZone( 'America/New_York' ) );
				?>
 
				<?php echo $start->format( 'l F jS' ); ?> - This event takes place all day.
			</div>
		<?php else: ?>	
			<div class="dates">
				<?php
					$start = new DateTime( $event->start->dateTime );
					$start->setTimezone( new DateTimeZone( 'America/New_York' ) );
 
					$end = new DateTime( $event->end->dateTime );
					$end->setTimezone( new DateTimeZone( 'America/New_York' ) );
 
					echo $start->format( 'l F jS g:ia' ) . ' - ' . $end->format( 'l F jS g:ia' );
				?>
			</div>
		<?php endif; ?>
 
		<div class="body">
			<?php echo $body; ?>
		</div>
 
		<?php if( strlen( $event->location->displayName ) > 0 ): ?>
			<div class="location">
				<label>Location: </label> <?php echo $event->location->displayName; ?>
			</div>
		<?php endif; ?>
	</div>
<?php endforeach; ?>