Login with Microsoft Account in PHP

Microsoft enables web applications to allow users to log in with their Outlook or Microsoft account via the OAuth 2.0 system. Learn how to implement login with a Microsoft account in PHP using the Microsoft Identity Platform in simple steps.

Login with Microsoft Account in PHP

Microsoft Identity Platform provides OAuth authentication, just like logging in with Google OAuth and logging in with GitHub OAuth as an authentication service for web applications. We can allow users to sign in with their Microsoft account using Microsoft's identity platform without having to fill out a long registration form. This post demonstrates how to implement login with Microsoft in a PHP application in simple steps. To implement login with Microsoft, we will create the following files:

  1. constants.php: The constants file to store our Microsoft credentials.
  2. microsoft-oauth-client.php: A PHP class to make API requests to Microsoft endpoints.
  3. index.php: The HTML file with the Microsoft login button.
  4. logout.php: A PHP file to allow users to log out of Microsoft.
  5. style.css: The CSS stylesheet for the HTML page and login button.
 

How to Integrate Login with Microsoft Account in PHP

In order to allow users to log in with a Microsoft account in a PHP application, we need to follow some simple steps. We need an Azure Application, Microsoft client ID and client secret, prepare Microsoft authorization URL to fetch Microsoft OAuth code, fetch Microsoft OAuth token for code and finally request user data from Microsoft Graph API with an API request. The following are the steps to implement sign-in with Microsoft in PHP:

 

Step 1: Register Microsoft Azure Application

To allow users to log in with their Microsoft account, we first need to register the Microsoft Azure App in the app registration portal. We then need application ID, directory ID, client ID and client secret for our API requests.

  • Go to the Microsoft Azure App registration portal.
  • Navigate to Azure Active Directory ➜ App Registrations ➜ New Registration.
  • Enter App Name for your application.
  • Enter the Redirect URI, which is the URL of the web application to which the user will be redirected after authorization.
  • After our app registration, we need the application ID, directory ID, client ID and client secret to make an API request to Microsoft from our PHP web application.
  • Client ID and client secret can be created under the section "Certificates & Secrets".
 

Step 2: Save Microsoft Client ID and Client Secret

Next, we need to store our Microsoft client ID and client secret to make API requests to Microsoft endpoints.

constants.php

<?php
define('BASE_URL', 'https://' . filter_input(INPUT_SERVER, 'SERVER_NAME', FILTER_SANITIZE_URL) . '/');
define('APPLICATION_ID', 'YOUR_MICROSOFT_APPLICATION_ID');
define('DIRECTORY_ID', 'YOUR_MICROSOFT_DIRECTORY_ID');
define('CLIENT_ID', 'YOUR_MICROSOFT_CLIENT_ID');
define('CLIENT_SECRET', 'YOUR_MICROSOFT_CLIENT_SECRET');
 

Step 3: Create a Microsoft OAuth Client Class

We need a centralized PHP class to make API requests to Microsoft endpoints. Using a PHP class will avoid a bloated index file. The class will contain two public methods: get_access_token() to retrieve an access token from Microsoft, and get_authenticated_user() to fetch Microsoft Graph user information of the authenticated user. Both methods will utilize a private function curl_request() to make cURL requests.

  • Add two private class properties $client_id and $client_secret for use in our class methods.
  • Add a method get_access_token() to fetch an access token from the Microsoft authorization endpoint URL for a provided OAuth code.
  • Add a method get_authenticated_user() to fetch data of the authenticated user from the Microsoft Graph user endpoint.
  • Finally, add a private method curl_request() to handle API requests and responses. This method will send a cURL request to Microsoft API endpoints provided as a parameter.

microsoft-oauth-client.php

<?php

class microsoft_oauth_client
{
private string $client_id;
private string $client_secret;

public function __construct($client_id, $client_secret)
{
$this->client_id = $client_id;
$this->client_secret = $client_secret;
}

/**
* @param string $oauth_code
* @param string $redirect_uri
* @return mixed
* @throws Exception
*/
public function get_access_token(string $oauth_code, string $redirect_uri): mixed
{
$api_url = 'https://login.microsoftonline.com/common/oauth2/v2.0/token';

$headers = [
'content-type' => 'application/x-www-form-urlencoded'
];

$body_data = http_build_query([
'client_id' => $this->client_id,
'client_secret' => $this->client_secret,
'code' => $oauth_code,
'scope' => 'https://graph.microsoft.com/.default',
'redirect_uri' => $redirect_uri,
'grant_type' => 'authorization_code',
]);

$response = json_decode($this->curl_request($api_url, 'POST', $headers, $body_data));

return $response->access_token;
}

/**
* @param string $access_token
* @return mixed
* @throws Exception
*/
public function get_authenticated_user(string $access_token): mixed
{
$api_url = 'https://graph.microsoft.com/v1.0/me';

return json_decode($this->curl_request($api_url, 'GET',
[
'Authorization' => sprintf('Bearer %s', $access_token),
]
));

}

/**
* @param string $url
* @param string $method
* @param array $headers
* @param array|string $body
* @param array $curl_options
* @return bool|string
* @throws Exception
*/
private function curl_request(string $url, string $method = 'GET', array $headers = [], array|string $body = [], array $curl_options = []): bool|string
{
$curl = curl_init();

array_change_key_case($headers, CASE_LOWER);

$headers = array_merge(['accept' => 'application/json'], $headers);

curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_TIMEOUT, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

if (str_starts_with($url, 'https://')) {
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
}

// If any headers are set, add them to curl request
if (!empty($headers)) {
curl_setopt($curl, CURLOPT_HTTPHEADER, array_map(function ($key, $value) {
return $key . ': ' . $value;
}, array_keys($headers), array_values($headers)));
}

// Set the request type , GET, POST, PUT or DELETE
switch (strtoupper($method)) {
case 'POST':
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
break;
case 'PUT':
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
break;
case 'DELETE':
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
break;
default:
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
break;
}

// Add content/body data to send with request
if (!empty($body)) {
curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
}

// Any extra curl options to add to curl object
if (!empty($curl_options)) {
foreach ($curl_options as $option_key => $option_value) {
curl_setopt($curl, $option_key, $option_value);
}
}

$response = curl_exec($curl);

$error = curl_error($curl);

$error_code = curl_errno($curl);

$status_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);

if ($error_code > 0) {
throw new Exception($error, $error_code);
}

if ($status_code !== 200) {
throw new Exception($response, $status_code);
}

curl_close($curl);

return $response;
}
}
 

Step 4: Create a Login with Microsoft Button

Next, we need our main HTML file as a user interface with a login with Microsoft button to allow users to sign in. The flow will be as follows:

  • Start a session at the very top of the page if it is not already started.
  • Include the constants file and the Microsoft client class.
  • Create a $microsoft_oauth_client instance providing the client ID and client secret.
  • Check access token is already in session, then fetch the authenticated user details from Microsoft.
  • Check in the URL if there is a "code" query parameter set, which is added when the user is redirected back from the Microsoft authorization page. Get the access token from Microsoft for the given OAuth code and redirect the user to the same page.
  • In HTML, check if the access token is set in the session, then user details are already fetched and displayed.
  • Display the login with Microsoft button if the access token is not set in the session.

index.php

<?php
if (!session_id()) {
session_start();
}

include_once 'constants.php';
include_once 'microsoft-oauth-client.php';

$microsoft_oauth_client = new microsoft_oauth_client(CLIENT_ID, CLIENT_SECRET);

if (isset($_SESSION['access_token'])) {
$user = $microsoft_oauth_client->get_authenticated_user($_SESSION['access_token']);

/**
* YOU CAN STORE USER INFORMATION TO DATABASE HERE
*/
}

$code = filter_input(INPUT_GET, 'code');

if (!empty($code)) {
$access_token = $microsoft_oauth_client->get_access_token(BASE_URL . 'login-with-microsoft-account-in-php');

$_SESSION['access_token'] = $access_token;

header('location: ' . BASE_URL . 'login-with-microsoft-account-in-php');
exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Login with Microsoft Account in PHP - Demo</title>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport"/>
<link rel="stylesheet" href="css/style.css"/>
</head>
<body>
<section class="section py-4">
<div class="container">
<?php if (isset($_SESSION['access_token'])) { ?>
<h3>You are logged in as:</h3>
<div class="user-details-container">
<div class="user-details">
<div>
<label>User ID:</label>
<span><?= $user->id; ?></span>
</div>
<div>
<label>Name:</label>
<span><?= $user->name; ?></span>
</div>
<div>
<a href="logout.php" rel="nofollow">Logout</a>
</div>
</div>
</div>
<?php } else { ?>
<a href="<?= sprintf('https://login.microsoftonline.com/common/oauth2/v2.0/authorize?%s', http_build_query([
'client_id' => CLIENT_ID,
'response_type' => 'code',
'response_mode' => 'query',
'scope' => 'openid profile email offline_access User.Read',
'redirect_uri' => BASE_URL . 'login-with-microsoft-account-in-php',
])); ?>" class="btn-microsoft" rel="nofollow">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.16675 9.1665H2.50008L2.50008 2.49984L9.16675 2.49984V9.1665Z" fill="#FF5722"/>
<path d="M17.5 9.1665H10.8333V2.49984L17.5 2.49984V9.1665Z" fill="#4CAF50"/>
<path d="M17.5 17.5H10.8333V10.8333H17.5V17.5Z" fill="#FFC107"/>
<path d="M9.16675 17.5H2.50008L2.50008 10.8333H9.16675V17.5Z" fill="#03A9F4"/>
</svg>

<span>Login with Microsoft</span>
</a>
<?php } ?>
</div>
</section>
</body>
</html>
 

Step 5: Create Logout From Microsoft OAuth (PHP)

Next, we create a PHP file to allow users to log out from our web application and redirect the user to the Microsoft logout URL.

logout.php

<?php
if (!session_id()) {
session_start();
}

include_once 'constants.php';

unset($_SESSION['access_token']);

header('Location:' . sprintf('https://login.microsoftonline.com/common/oauth2/v2.0/logout?post_logout_redirect_uri=%s', urlencode(BASE_URL . 'login-with-microsoft-account-in-php')));
 

Step 6: Add CSS Styles for Microsoft HTML

Next, we add CSS styles for index.php, which contains the sign-in with Microsoft button and Microsoft user graph summary.

style.css

* {
box-sizing: border-box;
text-decoration: none;
}
html,body {
margin: 0;
padding: 0;
}
body {
background-color: #f6f6f6;
font-family: "Segoe UI", "Roboto", "Helvetica", sans-serif;
font-size: 15px;
font-weight: normal;
font-style: normal;
line-height: 1.5;
}
.container {
width: 100%;
max-width: 1140px;
margin-right: auto;
margin-left: auto;
padding-right: 15px;
padding-left: 15px;
}
.py-4 {
padding-top: 1rem;
padding-bottom: 1rem;
}
.user-details-container {
background-color: #ffffff;
border: 1px solid #dddddd;
display: inline-flex;
gap: 1rem;
padding: 1rem;
}
.btn-microsoft{
background-color: #ffffff;
display: inline-block;
color: #1f2328;
border: 1px solid #1f2328;
padding: 0.5rem 1rem;
}
.btn-microsoft:hover{
background-color: #1f2328;
color: #ffffff;
}
.btn-microsoft svg{
vertical-align: middle;
}
.btn-microsoft span{
display: inline-block;
margin-left: 0.5rem;
}

Following these steps, we can now securely implement Login with Microsoft Account in PHP using OAuth 2.0 and allow users to sign in with Outlook or any Microsoft account without manual registration.