Skip to content

Instantly share code, notes, and snippets.

@DragonBe
Last active November 20, 2023 11:24
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save DragonBe/8af1044185ef14e61cd98e6086e3fc59 to your computer and use it in GitHub Desktop.
Save DragonBe/8af1044185ef14e61cd98e6086e3fc59 to your computer and use it in GitHub Desktop.
A simple PoC to access Azure AD for authentication
<?php
declare(strict_types=1);
use League\OAuth2\Client\Provider\GenericProvider;
use Microsoft\Graph\Graph;
use Microsoft\Graph\Model;
const APP_SESS_ID = 'AZPHPSID';
const OAUTH_APP_ID = '';
const OAUTH_APP_SECRET = '';
const OAUTH_REDIRECT_URI = '/callback';
const OAUTH_SCOPES = 'openid profile offline_access user.read';
const OAUTH_AUTHORITY = 'https://login.microsoftonline.com/common';
const OAUTH_AUTHORIZE_ENDPOINT = '/oauth2/v2.0/authorize';
const OAUTH_TOKEN_ENDPOINT = '/oauth2/v2.0/token';
$title = 'Hello public world!';
require_once __DIR__ . '/vendor/autoload.php';
//
// THIS IS A PROOF OF CONCEPT! DO NOT USE IN PRODUCTION!!!
//
$https = false;
if (isset($_SERVER['HTTPS'])) {
$https = true;
} elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO']) {
$https = true;
}
// Get the root op the application
$host = sprintf('%s://%s', ($https ? 'https' : 'http'), $_SERVER['HTTP_HOST']);
// Simple PHP routing
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$requestPath = rtrim($path, '/');
$user = null;
// If we run buit-in PHP web server, we want static files to be served directly
if ('cli-server' === php_sapi_name()) {
$staticExtensions = ['jpg', 'jpeg', 'gif', 'png', 'ico', 'js', 'css'];
$currentExtension = pathinfo($path, PATHINFO_EXTENSION);
if (in_array($currentExtension, $staticExtensions)) {
return false;
}
}
session_name(APP_SESS_ID);
session_start();
// Checking for user
$user = [];
if (isset($_SESSION['user'])) {
$user = unserialize($_SESSION['user']);
$title = 'Hello private world';
}
// Checking for messages
$style = 'success';
$displayMessage = '';
if (isset($_GET['type']) && isset($_GET['message'])) {
$styles = ['success', 'error'];
if (in_array($_GET['type'], $styles)) {
$style = $_GET['type'];
}
$displayMessage = $_GET['message'];
}
if ('/logout' === $requestPath) {
session_destroy();
setcookie(APP_SESS_ID, '', time() - 1000);
header('Location: ' . $host . '/?type=success&message=Succesfully%20logged%20out');
}
if ('/login' === $requestPath) {
$oAuthClient = new GenericProvider([
'clientId' => OAUTH_APP_ID,
'clientSecret' => OAUTH_APP_SECRET,
'redirectUri' => $host . OAUTH_REDIRECT_URI,
'urlAuthorize' => OAUTH_AUTHORITY . OAUTH_AUTHORIZE_ENDPOINT,
'urlAccessToken' => OAUTH_AUTHORITY . OAUTH_TOKEN_ENDPOINT,
'urlResourceOwnerDetails' => '',
'scopes' => OAUTH_SCOPES,
]);
$authUrl = $oAuthClient->getAuthorizationUrl();
$_SESSION['oauthState'] = $oAuthClient->getState();
header('Location: ' . $authUrl);
}
if ('/callback' === $requestPath) {
$expectedState = $_SESSION['oauthState'];
unset($_SESSION['oauthState']);
if (!isset($_GET['state']) || !isset($_GET['code'])) {
header('Location: ' . $host . '/?type=error&message=No%20OAuth%20session');
}
$providedState = $_GET['state'];
if (!isset($expectedState)) {
// If there is no expected state in the session,
// do nothing and redirect to the home page.
header('Location: ' . $host . '/?type=error&message=Expected%20state%20not%20available');
}
if (!isset($providedState) || $expectedState != $providedState) {
header('Location: ' . $host . '/?type=error&message=State%20does%20not%20match');
}
// Authorization code should be in the "code" query param
$authCode = $_GET['code'];
if (isset($authCode)) {
// Initialize the OAuth client
$oAuthClient = new GenericProvider([
'clientId' => OAUTH_APP_ID,
'clientSecret' => OAUTH_APP_SECRET,
'redirectUri' => $host . OAUTH_REDIRECT_URI,
'urlAuthorize' => OAUTH_AUTHORITY . OAUTH_AUTHORIZE_ENDPOINT,
'urlAccessToken' => OAUTH_AUTHORITY . OAUTH_TOKEN_ENDPOINT,
'urlResourceOwnerDetails' => '',
'scopes' => OAUTH_SCOPES,
]);
$accessToken = null;
try {
// Make the token request
$accessToken = $oAuthClient->getAccessToken('authorization_code', [
'code' => $authCode
]);
} catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
header('Location: ' . $host . '/?type=error&message=' . urlencode($e->getMessage()));
}
}
$user = [];
if (null !== $accessToken) {
$graph = new Graph();
$graph->setAccessToken($accessToken->getToken());
try {
$azureUser = $graph->createRequest('GET', '/me?$select=displayName,mail,userPrincipalName')
->setReturnType(Model\User::class)
->execute();
} catch (Exception $exception) {
header('Location: ' . $host . '/?type=error&message=' . urlencode('Unable to get user details: ' . $exception->getMessage()));
}
$user = [
'name' => $azureUser->getDisplayName(),
'email' => $azureUser->getMail(),
];
$_SESSION['user'] = serialize($user);
}
header('Location: ' . $host);
}
?>
<!DOCTYPE html>
<html lang="en_US">
<head>
<meta charset="UTF-8">
<title><?php echo htmlentities($title, ENT_QUOTES, 'UTF-8') ?></title>
<style type="text/css">
html {
font-family: Helvetica, Arial, sans-serif;
}
.error, .success {
padding: 5px 15px;
}
.error {
background-color: lightpink;
border: 1px solid darkred;
color: darkred;
}
.success {
background-color: lightgreen;
border: 1px solid darkgreen;
color: darkgreen;
}
</style>
</head>
<body>
<h1><?php echo htmlentities($title, ENT_QUOTES, 'UTF-8') ?></h1>
<p>Welcome to PHP <strong><?php echo phpversion() ?></strong> on Azure App Service <strong><?php echo gethostname() ?></strong>.</p>
<p>
<a href="/">Home</a>
<a href="/login">Login</a>
<a href="/logout">Logout</a>
</p>
<?php if ('' !== $displayMessage): ?>
<div class="<?php echo $style ?>">
<p><?php echo htmlentities($displayMessage, ENT_QUOTES, 'UTF-8') ?></p>
</div>
<?php endif ?>
<?php if ([] !== $user): ?>
<p>User details</p>
<ul>
<li><strong>Name:</strong> <?php echo htmlentities($user['name'], ENT_QUOTES, 'UTF-8') ?></li>
<li><strong>Email:</strong> <?php echo htmlentities($user['email'], ENT_QUOTES, 'UTF-8') ?></li>
</ul>
<?php endif ?>
</body>
</html>
@heper
Copy link

heper commented Nov 20, 2023

hallo,

i'm looking for an 'authenticate with microsoft' solution for an intranet website in a school.
I've been trying to get it to work but unfortunately i'm getting an error on line 141 $graph = new Graph()

Uncaught Error: Class 'Microsoft\Graph\Graph' not found in .....__

I assume it has something todo with the version composer is pulling in. This is what i have in composer.json:
"require": {
"microsoft/microsoft-graph": "^2.0"
}

could you tell me what i'm doing wrong ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment