Overview
What are we building today?
We do have a Web APP API running in an Azure App Service that is protected with Azure Active Directory (AAD). We want to access this webservice from a PHP website. In our setup the php website runs in a local docker container. The first and foremost goal is to show how we can get hands on the access token from our PHP application.
- Request the Index.php through http://localhost:90
- Use the OAuth2 library thenetworg/oauth2-azure to request an access token
- Authenticate against the app phpDemo in AAD and request access to ressource weatherapi
- Return the access token
- Return access token. Here you could call the web service with the returned bearer token
- Render the token on the website
- Use Postman to call the protected webservice
In the following sections contain a step by step guidance how to implement this scenario.
Creating the API-Application
Open Visual Studio 2019 and create a new „ASP.NET Core Web App“
- Name: weatherapi
- Plattform: .NET Core / ASP.NET Core 3.1
- Template: API
In the solution explorer right click the project – Publish…
- Azure
- Azure App Service (Windows)
- Select your subscription
- + Create a new Azure App Service …
- Name: weatherapi (select a unique name)
- Subscription: Your Subscription
- Resource Group: New… (phpdemo)
- Hosting Plan: New… (testplan)
-
- Click Create to create the Azure Resources
- Select the web app and click „Finish“
- Click Publish to publish the WebApp
Now you should be able to call your webservice under following URL: https://weatherapi.azurewebsites.net/weatherforecast
Create AAD App for ASP.NET API with weather.read
- Open https://portal.azure.com
- Navigate to Azure Active Directory / App registrations
- + New registration
- Name: weatherapi
- Account Types: Single Tenant
- Redirect URI: Web – http://localhost:90
- Register
- Write down ClientID. In my case it is: b37*****b02
- Click on the button „Endpoints“
- Copy the „OpenID Connect metadata document“ Url. In my case: https://login.microsoftonline.com/e2****3d/v2.0/.well-known/openid-configuration where e2***3d is my tenant id.
- Copy the „OAuth 2.0 authorization endpoint (v2)“
https://login.microsoftonline.com/e2**3d/oauth2/v2.0/authorize - Copy the „OAuth 2.0 token endpoint (v2)“
https://login.microsoftonline.com/e2**3d/oauth2/v2.0/token
- Navigate to Manage – Expose an API
- Application ID Uri (Set)
- You can use the given suggestion or define your own. In my case: api://b37******02
- Application ID Uri (Set)
- Navigate to Manage – Manifest
- Search for „accessTokenAcceptedVersion“ : null, and replace it with „accessTokenAcceptedVersion“ : 2,
This will ensure that we receive OAuth 2.0 tokens! If you examine the JWT-Token in f.e. https://jwt.ms you will find the version set to: „ver“: „2.0“. - Look out for „appRoles“: []
- Use GuidGen to create a new GUID (f.e. 4B****08)
- Insert the following:
- Search for „accessTokenAcceptedVersion“ : null, and replace it with „accessTokenAcceptedVersion“ : 2,
"appRoles": [ { "allowedMemberTypes": ["Application" ], "description": "Weather API", "displayName": "Weather API", "id" : "4B*************08", "isEnabled": true, "lang" : null, "origin": "Application", "value": "weather.read" } ],
Securing the API Application with Easy Auth
- Navigate to Azure App Services
- Select your weatherapi Application
- Under Settings click Authentication / Authorization
- Turn App Service Authentication ON
- In the drop down select „Log in with Azure Active Directory“
- Click „Azure Active Directory“
- Select Advanced
- Copy ClientID to Client ID field
- Copy „OpenID Connect metadata document“ to Issuer Url
- Click OK
- Save
Take care with the Issuer URL, because your application might break if you use JWT-Tokens with a „wrong“ issuer. JWT-Tokens with Ver 1.0 have a different Issuer than JWT-Tokens Ver 2.0.
Open the OpenID Connect Metadata Url in a browser and locate the „issuer“ element. It will be set to:
If you use V1 Tokens you need to set Issue in Easy Auth to
The „iss“ element in the tokens must match the issuer configured in EasyAuth! Read more on Access Tokens V1/V2 here!
Create AAD App for PHP Application
- Open https://portal.azure.com
- Navigate to Azure Active Directory / App registrations
- + New registration
- Name: phpdemo
- Account Types: Single Tenant
- Redirect URI: Web – http://localhost:90
- Register
- Write down ClientID. In my case it is: c9e*****9ea
- Click on the button „Endpoints“
- Copy the „OpenID Connect metadata document“ Url. In my case: https://login.microsoftonline.com/e2****3d/v2.0/.well-known/openid-configuration
- Click on Manage – Certificates & secrets
- + New client secret
- Name: mysecret
- Expiry: 2 Years
- Copy down the Secret (we need that later). In my case its: AKX**********
- + New client secret
- Click on Manager – API Permissions
- + Add a permission
- Select „My APIs“-Tab
- Select „weatherapi“
- Select „Application permissions“
- Select „weather.read“
- Add Permissions
- Note the orange exclamation sign! Use „Grant admin consent for…“ button next to „+ Add permission“ and confirm with Yes.
- + Add a permission
Creating the PHP Application
Since I did not want to install all PHP stuff on my machine I decided to develop my example in a docker container. Thanks to the TruthSeekers who wrote this excellent post on how to do exactly that. You can clone the source code here.
After I cloned the git repository I had to adopt my docker-compose.yml file slightly since port 80 / 8080 are already consumed on my machine.
... ports: - 90:80 ... ports: - 9090:8080 ...
-
docker-compose up -d
which brought up all containers, including SQL, which we won’t be needing now. Since we need some OAuth-Libraries for PHP, I decided to use the package manager tool composer.
I did a quick „docker container list“ to figure out the php container.
Then with
-
docker exec -it php-docker-simple_php_1 bash
I connect to the bash of the running container.
Execute the following statements to install composer:
apt-get update apt-get install zip unzip Cd ~ php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" php -r "if (hash_file('sha384', 'composer-setup.php') === '795f976fe0ebd8b75f26a6dd68f78fd3453ce79f32ecb33e7fd087d39bfeb978342fb73ac986cd4f54edd0dc902601dc') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" php composer-setup.php php -r "unlink('composer-setup.php');"
As OAuth2 library I want to use „thenetworg/oauth2-azure“ which can be found here.
It is based on the OAuth2 Library „thephpleague/oauth2-client“ which can be found here.
Then install this package to the sample which resides in /var/www/html:
cd /var/www/html php ~/composer.phar require thenetworg/oauth2-azure
Exit to the terminal and start VS-Code in the local directory or any other editor of your choice
For our sample we need following information which we collected earlier:
- Client ID of the phpdemo app
- ClientSecret of the phpdemo app
- redirectUri of phpdemo app
- aad tenant id
- OAuth 2.0 Authorize Url
- OAuth 2.0 Token Url
- Client ID of the weatherapi app
We need all these values and add them in the following code fragment which initializes the oauth provider for Azure AAD:
$provider = new TheNetworg\OAuth2\Client\Provider\Azure([ 'clientId' => 'c9e*****9ea', 'clientSecret' => 'AKX********', 'redirectUri' => 'http://localhost:90', 'tenant' => 'e2*******3d', 'urlAuthorize' => 'https://login.microsoftonline.com/e2*******3d/oauth2/v2.0/authorize', 'urlAccessToken' => 'https://login.microsoftonline.com/e2*******3d/oauth2/v2.0/token', 'urlAPI' => 'b37*******b02', 'scope' => 'b37*******b02/.default' ]); $provider->defaultEndPointVersion = TheNetworg\OAuth2\Client\Provider\Azure::ENDPOINT_VERSION_2_0;
We can now retrieve the access token with the following code:
$accessToken = $provider->getAccessToken('client_credentials', [ 'scope'=> $provider->scope ]);
<?php echo "OAuth Sample<br/>"; /* Make sure we include necessary libraries */ require_once(__DIR__."/vendor/autoload.php"); /* Initialize provider */ $provider = new TheNetworg\OAuth2\Client\Provider\Azure([ 'clientId' => 'c9e*****9ea', 'clientSecret' => 'AKX********', 'redirectUri' => 'http://localhost:90', 'tenant' => 'e2*******3d', 'urlAuthorize' => 'https://login.microsoftonline.com/e2*******3d/oauth2/v2.0/authorize', 'urlAccessToken' => 'https://login.microsoftonline.com/e2*******3d/oauth2/v2.0/token', 'urlAPI' => 'b37*******b02', 'scope' => 'b37*******b02/.default' ]); $provider->defaultEndPointVersion = TheNetworg\OAuth2\Client\Provider\Azure::ENDPOINT_VERSION_2_0; try { $accessToken = $provider->getAccessToken('client_credentials', [ 'scope' => $provider->scope ]); } catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) { // Failed to get the access token exit($e->getMessage()); } echo "Access-Token:"; echo $accessToken;
Now we can call http://localhost:90 on our machine and retrieve the JWT Bearer Token.
Open Postman and make a get request to:
In the Authorization TAB select type: „Bearer Token“ and paste the access token to the token field.
If you hit Send now, you will retrieve the results of the weatherforecast.
That’s it. Thanks
Andreas