Azure : Using PHP to go all oauth2 on the management API!

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…

active-directory-oauth-code-flow-native-app

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.

2016-10-21-20_34_15-active-directory-microsoft-azure

Also be sure to set the application to “multi-tenant”.

2016-10-21-20_37_03-active-directory-microsoft-azure

And then generate your key… Be sure to note this down.

2016-10-21-20_36_58-active-directory-microsoft-azure

Just like with the client id!

2016-10-21-20_38_17-active-directory-microsoft-azure

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 ;

 

<?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.

8 thoughts on “Azure : Using PHP to go all oauth2 on the management API!

  1. 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

  2. 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?

  3. 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

  4. 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”;
    }

  5. 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.

  6. 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

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.