Introduction
As a hobby effort, I wanted to create a small poc where any user would be able to login with their AAD user, grant access to an application, after which that application could query their subscriptions.
In all honesty, I’ve been struggling more than I like to admit with getting this working… So this post will cover all the steps that you need to do to get this working!
Oauth & Azure AD
Before getting our hands dirty, read up on the following post ; Authorize access to web applications using OAuth 2.0 and Azure Active Directory
Ready it thoroughly! To be honest, I didn’t at first and it cost me a lot of time. 😉
Anyhow, the flow looks as follows…
So basically;
- We’ll redirect the user to sign-in (and if this hasn’t been done, grant our application access)
- If all went well, we’ll receive an authorization code
- We’ll use this code to get a bearer (and refresh) token
- Next up we’ll use the bearer code to connect to the Azure REST API for getting the list of subscriptions for that user.
Prep on Azure AD
First start by creating a web application on Azure Active Directory. Be sure to set your reply url correct… AND (important) add “Windows Azure Service Management” as an additional application. Grant the delegated permission too.
Also be sure to set the application to “multi-tenant”.
And then generate your key… Be sure to note this down.
Just like with the client id!
Important ; Be aware that the key will include the applications you have added. So… if you changed the application permissions, then you will need to generate a new key!
Code Sample – Curl
Below you can find a quick & dirty code sample with just using curl…
<?php session_start(); error_reporting(-1); ini_set('display_errors', 'On'); if (!isset($_GET['code'])) { $authUrl = "https://login.microsoftonline.com/common/oauth2/authorize?"; $authUrl .= "client_id=your-client-id"; $authUrl .= "&response_type=code"; $authUrl .= "&redirect_uri=http%3A%2F%2Fauth.kvaes.be%2Findex.php"; $authUrl .= "&response_mode=query"; $authUrl .= "&resource=https%3A%2F%2Fmanagement.azure.com%2F"; $authUrl .= "&state=12345"; header('Location: '.$authUrl); exit; } else { $accesscode = $_GET['code']; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL,"https://login.microsoftonline.com/common/oauth2/token"); curl_setopt($ch, CURLOPT_POST, 1); $client_id = "your-client-id"; $client_secret = "your-client-secret"; curl_setopt($ch, CURLOPT_POSTFIELDS, "grant_type=authorization_code&client_id=".$client_id."&redirect_uri=http%3A%2F%2Fauth.kvaes.be%2Findex.php&resource=https%3A%2F%2Fmanagement.azure.com%2F&&code=".$accesscode."&client_secret=".urlencode($client_secret)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $server_output = curl_exec ($ch); curl_close ($ch); $jsonoutput = json_decode($server_output, true); $bearertoken = $jsonoutput['access_token']; $url = "https://management.azure.com/subscriptions/?api-version=2015-01-01"; $ch = curl_init($url); $User_Agent = 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31'; $request_headers = array(); $request_headers[] = 'User-Agent: '. $User_Agent; $request_headers[] = 'Accept: application/json'; $request_headers[] = 'Authorization: Bearer '. $bearertoken; curl_setopt($ch, CURLOPT_HTTPHEADER, $request_headers); $result = curl_exec($ch); curl_close($ch); echo $result; } ?>
The most important things to note ;
- We’ll be using “common” as tenant in the oauth authorize uri. This will ensure that this sample works for all tenants and not just a single one.
- The redirect uri should map the one you configured in your application.
- The resource should be included, where we’ll be using the “management.azure.com” to get a bearer token that applies to this target.
- This code sample does not facilitate refresh tokens.
Code Sample – Oauth 2.0 Client
The following code sample is about the same, but this will leverage two libraries ;
- TheNetworg\oauth2-azure as a library for being an oauth2 client
- Guzzle as HTTP client library
<?php session_start(); require __DIR__ . '/vendor/autoload.php'; error_reporting(-1); ini_set('display_errors', 'On'); $provider = new TheNetworg\OAuth2\Client\Provider\Azure([ 'clientId' => 'your-client-id', 'clientSecret' => 'your-client-secret', 'redirectUri' => 'http://auth.kvaes.be/index.php', 'resource' => 'https://management.azure.com/' ]); if (!isset($_GET['code'])) { // If we don't have an authorization code then get one $authUrl = $provider->getAuthorizationUrl(); $_SESSION['oauth2state'] = $provider->getState(); header('Location: '.$authUrl); exit; } else { // Try to get an access token (using the authorization code grant) $token = $provider->getAccessToken('authorization_code', [ 'code' => $_GET['code'] ]); $accesstoken = $provider->getAccessToken('refresh_token', [ 'refresh_token' => $token->getRefreshToken(), 'resource' => 'https://management.core.windows.net/' ]); $bearertoken = "Bearer " . $accesstoken->getToken(); $client = new GuzzleHttp\Client([ 'base_uri' => 'https://management.azure.com/', 'timeout' => 2.0, ]); try { $result = $client->request('GET', "/subscriptions/?api-version=2015-01-01", [ 'headers' => [ 'User-Agent' => 'testing/1.0', 'Accept' => 'application/json', 'Authorization' => $bearertoken ] ]); } catch (RequestException $e) { echo Psr7\str($e->getRequest()); if ($e->hasResponse()) { echo Psr7\str($e->getResponse()); } } echo $result->getBody(); } ?>
Most important things to note here ;
- Be sure to add the resource to the provide that covers the Azure API
- All remarks from previous code also apply here… 😉
TL;DR
- The oauth approach can provide you with a nice approach to act on behalf of a user.
- Access tokens have a limited lifetime. This can be configured on tenant level. Which will be a balance between security & usability.
- The common endpoint is used when you are looking for a multi tenant approach.
Hi,
Many thanks for sharing the code but I’m getting resource error whenever I’m running your code.
The below error I’m getting
AADSTS650057: Invalid resource. The client has requested access to a resource which is not listed in the requested permissions in the client’s application registration. Client app ID: 2b3fae7c-932c-47d5-80d6-200d2b21cc7d(Arehman). Resource value from request: https://management.azure.com/. Resource app ID: 797f4846-ba00-4fd7-ba43-dac1f8f63013. List of valid resources from app registration: 00000003-0000-0000-c000-000000000000.
Please help me I think it is related to Resource id
Find your inspiration here ; https://docs.microsoft.com/en-us/azure/kusto/management/access-control/how-to-provision-aad-app (troubleshooting down below)
Hello
I am first time working with AZURE.
I what make page (test.php) where user must use offcie365 email to login and see page content
In my test.php I will have like this code, its correct?
session_start();
error_reporting(-1);
ini_set(‘display_errors’, ‘On’);
if (!isset($_GET[‘code’])) {
$authUrl = “https://login.microsoftonline.com/common/oauth2/authorize?”;
$authUrl .= “client_id=your-client-id”;
$authUrl .= “&response_type=code”;
$authUrl .= “&redirect_uri=http%3A%2F%2Fauth.kvaes.be%2Findex.php”;
$authUrl .= “&response_mode=query”;
$authUrl .= “&resource=https%3A%2F%2Fmanagement.azure.com%2F”;
$authUrl .= “&state=12345”;
header(‘Location: ‘.$authUrl);
exit;
} else {
$accesscode = $_GET[‘code’];
echo “site content”;
}
And also how this code works anyone who have O365 mail can access or only mydoman users can access using its O365 mail?
Sorry code must be like this i think
If i use “/common/” this will allow anyone make authorization? I want make it only for my organization
code:
session_start();
error_reporting(-1);
ini_set(‘display_errors’, ‘On’);
if (!isset($_GET[‘code’])) {
$authUrl = “https://login.microsoftonline.com/common/oauth2/authorize?”;
$authUrl .= “client_id=your-client-id”;
$authUrl .= “&response_type=code”;
$authUrl .= “&redirect_uri=http%3A%2F%2Fauth.kvaes.be%2Findex.php”;
$authUrl .= “&response_mode=query”;
$authUrl .= “&resource=https%3A%2F%2Fmanagement.azure.com%2F”;
$authUrl .= “&state=12345″;
header(‘Location: ‘.$authUrl);
exit;
} else {
$accesscode = $_GET[‘code’];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,”https://login.microsoftonline.com/common/oauth2/token”);
curl_setopt($ch, CURLOPT_POST, 1);
$client_id = “your-client-id”;
$client_secret = “your-client-secret”;
curl_setopt($ch, CURLOPT_POSTFIELDS,
“grant_type=authorization_code&client_id=”.$client_id.”&redirect_uri=http%3A%2F%2Fauth.kvaes.be%2Findex.php&resource=https%3A%2F%2Fmanagement.azure.com%2F&&code=”.$accesscode.”&client_secret=”.urlencode($client_secret));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$server_output = curl_exec ($ch);
curl_close ($ch);
$jsonoutput = json_decode($server_output, true);
if ($jsonoutput == true)
echo “Site Content”;
}
The post is about 4 years old. I would hope there are better oauth2 libraries for PHP by now… Best to look towards those tbh.
Can you give me advise, I make research and can not find such script, using curl for oauth2 (not libraries)
I need simple only authorization, if user makes authorization show site content
https://github.com/thenetworg/oauth2-azure this one could be an example, as one tailored to AAD based on https://github.com/thephpleague/oauth2-client