I've added a Microsoft OAuth service and i would like to share with community.
I take this opportunity to request that it be made configurable whether or not new users can be registered
<?php
public array $oauthConfigs = [
'microsoft' => [
'client_id' => 'Get it from Microsoft Entra ID',
'client_secret' => 'Get it from Microsoft Entra ID',
'allow_login' => true,
],
];
<?php
declare(strict_types=1);
namespace App\Libraries\ShieldOAuth;
use Datamweb\ShieldOAuth\Libraries\Basic\AbstractOAuth;
use Exception;
use stdClass;
class MicrosoftOAuth extends AbstractOAuth
{
private static $API_CODE_URL = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize';
private static $API_TOKEN_URL = 'https://login.microsoftonline.com/common/oauth2/token';
private static $API_USER_INFO_URL = 'https://graph.microsoft.com/v1.0/me';
private static $APPLICATION_NAME = 'ShieldOAuth';
protected string $token;
protected $client;
protected $config;
protected string $client_id;
protected string $client_secret;
protected string $callback_url;
public function __construct(string $token = '')
{
$this->token = $token;
$this->client = \Config\Services::curlrequest();
$this->config = new \Config\ShieldOAuthConfig();
$this->callback_url = base_url('oauth/' . $this->config->call_back_route);
$this->client_id = env('ShieldOAuthConfig.microsoft.client_id', $this->config->oauthConfigs['microsoft']['client_id']);
$this->client_secret = env('ShieldOAuthConfig.microsoft.client_secret', $this->config->oauthConfigs['microsoft']['client_secret']);
}
public function makeGoLink(string $state): string
{
try
{
if (empty($this->client_id))
{
throw new Exception('Microsoft Tenant ID is empty,');
}
if (empty($this->client_id))
{
throw new Exception('Microsoft Client ID is empty,');
}
if (empty($this->client_secret))
{
throw new Exception('Microsoft Secret is empty,');
}
$query = http_build_query([
'client_id' => $this->client_id,
'response_type' => 'code',
'redirect_uri' => $this->callback_url,
'response_mode' => 'query',
'approval_prompt' => 'auto',
'scope' => 'User.Read profile openid email',
'state' => $state
]);
$microsoftURL = self::$API_CODE_URL . '?' . $query;
return $microsoftURL;
}
catch (\Throwable $e)
{
die($e->getMessage());
}
}
public function fetchAccessTokenWithAuthCode(array $allGet): void
{
$client = \Config\Services::curlrequest();
try
{
$response = $client->request('POST', self::$API_TOKEN_URL, [
'form_params' => [
'client_id' => $this->client_id,
'client_secret' => $this->client_secret,
'grant_type' => 'authorization_code',
'redirect_uri' => $this->callback_url,
'code' => $allGet['code']
],
'http_errors' => false,
]);
$response = json_decode($response->getBody());
if (!empty($response->error))
{
throw new Exception($response->error);
}
$this->setToken($response->access_token);
}
catch (Exception $e)
{
die($e->getMessage());
}
}
public function fetchUserInfoWithToken(): object
{
try
{
$response = $this->client->request('GET', self::$API_USER_INFO_URL, [
'headers' => [
'Authorization' => 'Bearer ' . $this->getToken(),
],
'http_errors' => false,
]);
}
catch (Exception $e)
{
die($e->getMessage());
}
$response = json_decode($response->getBody());
$userInfo = new stdClass();
$userInfo->username = $response->userPrincipalName;
$userInfo->email = $response->mail;
$userInfo->first_name = $response->givenName;
$userInfo->last_name = $response->surname;
$userInfo->avatar = '';
return $userInfo;
}
public function setColumnsName(string $nameOfProcess, object $userInfo): array
{
if ($nameOfProcess === 'syncingUserInfo')
{
$usersColumnsName = [
$this->config->usersColumnsName['first_name'] => $userInfo->first_name,
$this->config->usersColumnsName['last_name'] => $userInfo->last_name,
//$this->config->usersColumnsName['avatar'] => $userInfo->last_name, // No get avantar from request
];
}
if ($nameOfProcess === 'newUser')
{
die('Auto-register users is disabled;');
// Commented because i not use register new users
// $usersColumnsName = [
// 'username' => $userInfo->username,
// 'email' => $userInfo->email,
// 'password' => random_string('crypto', 32),
// 'active' => TRUE,
// $this->config->usersColumnsName['first_name'] => $userInfo->first_name,
// $this->config->usersColumnsName['last_name'] => $userInfo->last_name,
// $this->config->usersColumnsName['avatar'] => $userInfo->avatar,
// ];
}
return $usersColumnsName;
}
}