This sample shows how to configure Azure AD to support protected service calls to protected Web APIs that call other protected Web APIs.
- .NET Core 6.0
- Visual Studio or VS Code
- Azure Active Direcotry
- Postman
In this sample I will use Postman as the client. However, it could also be a web application as well.
API1 is a simple Web API written in .NET Core 6.0. It's job is to ensure that the user is authenticated in AAD and has the appropriate rights. , it will then make an service call to API2.
API2 is acting as an orchestrator or broker to two other downstream APIs, API2a and API2b. Again, ensuring that the upstream API has been authenticated and has the appropriate rights.
These APIs are meant to represent calling a datasource, like SQL Server or Cosmos DB. However, the focus of sample is configuring AAD. I'm only returning dummy data that is hardcoded in the APIs.
-
Navigate to the Azure Portal > Azure Active Directory > App Registrations > + New Registration

-
Authentication
- Click on + Add a Platform > Web
- Enter the redirect API for the API Application. Which can be found in the api2a project > Properties > launchSettings.json. The format will be https://localhost:/signin-oidc
- Select the tokend you would like to be issued by the authoration endpoint:
- Access tokens checked
- who can use this application or access vi API?
- Accounts in this organizational directory only (single tenant)
-
Token configuration
-
Expose an API
- Here you can define scopes that you can use in your application to protect APIs and specific API calls. Click on + Add a scope with the folling information. You wil be prompted to set the Application ID URI. It will looking something like api://. Click Save and Continue.
-
App Roles
-
Manifest
-
In the Manifest change the following value
"accessTokenAcceptedVersion": null
-
To this value
"accessTokenAcceptedVersion": 2
-
Click Save
-
Now let's do the same thing for API2b. We'll add one additional step for API Permmissions.
- Navigate to the Azure Portal > Azure Active Directory > App Registrations > + New Registration
- Name: api2b
- Account Type: Accounts in the organization directory only
- Redirect URI: leave blank.
- Then click Register
- Authentication
- Click on + Add a Platform > Web
- Enter the redirect API for the API Application. Which can be found in the api2b project > Properties > launchSettings.json. The format will be https://localhost:/signin-oidc
- Select the tokend you would like to be issued by the authoration endpoint:
- Access tokens checked
- who can use this application or access vi API?
- Accounts in this organizational directory only (single tenant)
- Token configuration
- Here you can configure what claims you want to see in the token. As an example I added the auth_time and tenant_ctry claims to the Access Token?
- API Permmissions
- Expose an API
- Here you can define scopes that you can use in your application to protect APIs and specific API calls. Click on + Add a scope with the folling information. You wil be prompted to set the Application ID URI. It will looking something like api://. Click Save and Continue.
- Scope naem: api2b.Read
- Who can consent?: Admins only
- Admin consent display name: api2b.Read
- Admin consent description: api2b.Read
- State: Enabled
- Click Save
- Here you can define scopes that you can use in your application to protect APIs and specific API calls. Click on + Add a scope with the folling information. You wil be prompted to set the Application ID URI. It will looking something like api://. Click Save and Continue.
- App Roles
- Now click on App Roles > + Create app role
- . Display name: api2b-ReadonlyRole
- Allowed member types: User/Groups
- Value: api2b-ReadonlyRole
- Description: api2b-ReadonlyRole
- Do you wan to enable this app role? Checked
- Click Apply
- We will add a client application later
- Now click on App Roles > + Create app role
- Manifest
-
In the Manifest change the following value
"accessTokenAcceptedVersion": null
-
To this value
"accessTokenAcceptedVersion": 2
-
Click Save
-
Now let's do the same thing for API2. We'll add one additional step for API Certificate & Secrets.
- Navigate to the Azure Portal > Azure Active Directory > App Registrations > + New Registration
- Name: api2
- Account Type: Accounts in the organization directory only
- Redirect URI: leave blank.
- Then click Register
- Authentication
- Click on + Add a Platform > Web
- Enter the redirect API for the API Application. Which can be found in the api2 project > Properties > launchSettings.json. The format will be https://localhost:/signin-oidc
- Select the tokend you would like to be issued by the authoration endpoint:
- Access tokens checked
- who can use this application or access vi API?
- Accounts in this organizational directory only (single tenant)
- Certificates & secrets
- Token configuration
- Here you can configure what claims you want to see in the token. As an example I added the auth_time and tenant_ctry claims to the Access Token?
- API Permmissions
- Click on + Add a permission > My APIs > api2a
- Selected Delegated permissions
- Select api2a.Read
- Click Add permissions
- Click on Grant admin constent and Yes on the confirmation
- Click on + Add a permission > My APIs > api2b
- Selected Delegated permissions
- Select api2b.Read
- Click Add permissions
- Click on Grant admin constent and Yes on the confirmation

- Click on + Add a permission > My APIs > api2a
- Expose an API
- Here you can define scopes that you can use in your application to protect APIs and specific API calls. Click on + Add a scope with the folling information. You wil be prompted to set the Application ID URI. It will looking something like api://. Click Save and Continue.
- Scope naem: api2.Read
- Who can consent?: Admins only
- Admin consent display name: api2.Read
- Admin consent description: api2.Read
- State: Enabled
- Click Save
- Here you can define scopes that you can use in your application to protect APIs and specific API calls. Click on + Add a scope with the folling information. You wil be prompted to set the Application ID URI. It will looking something like api://. Click Save and Continue.
- App Roles
- Now click on App Roles > + Create app role
- . Display name: api2-ReadonlyRole
- Allowed member types: User/Groups
- Value: api2-ReadonlyRole
- Description: api2-ReadonlyRole
- Do you wan to enable this app role? Checked
- Click Apply
- We will add a client application later
- Now click on App Roles > + Create app role
- Manifest
-
In the Manifest change the following value
"accessTokenAcceptedVersion": null
-
To this value
"accessTokenAcceptedVersion": 2
-
Click Save
-
Now let's do the same thing for API1. We'll add one additional step for API Certificate & Secrets.
- Navigate to the Azure Portal > Azure Active Directory > App Registrations > + New Registration
- Name: api1
- Account Type: Accounts in the organization directory only
- Redirect URI: leave blank.
- Then click Register
- Authentication
- Click on + Add a Platform > Web
- Enter the redirect API for the API Application. Which can be found in the api1 project > Properties > launchSettings.json. The format will be https://localhost:/signin-oidc
- Select the tokend you would like to be issued by the authoration endpoint:
- Access tokens checked
- who can use this application or access vi API?
- Accounts in this organizational directory only (single tenant)
- Certificates & secrets
- Click on + New client secret
- Description: api1 Secret
- Expires: 6 months
- Click Add - Keep note of the Secret value as you will need it in your api2 appsettings.json file.
- Token configuration
- Here you can configure what claims you want to see in the token. As an example I added the auth_time and tenant_ctry claims to the Access Token?
- API Permmissions
- Click on + Add a permission > My APIs > api2
- Selected Delegated permissions
- Select api2.Read
- Click Add permissions
- Click on Grant admin constent and Yes on the confirmation
- Click on + Add a permission > My APIs > api2b
- Selected Delegated permissions
- Select api2.Read
- Click Add permissions
- Click on Grant admin constent and Yes on the confirmation
- Click on + Add a permission > My APIs > api2
- Expose an API
- Here you can define scopes that you can use in your application to protect APIs and specific API calls. Click on + Add a scope with the folling information. You wil be prompted to set the Application ID URI. It will looking something like api://. Click Save and Continue.
- Scope naem: api1.Read
- Who can consent?: Admins only
- Admin consent display name: api1.Read
- Admin consent description: api1.Read
- State: Enabled
- Click Save
- Here you can define scopes that you can use in your application to protect APIs and specific API calls. Click on + Add a scope with the folling information. You wil be prompted to set the Application ID URI. It will looking something like api://. Click Save and Continue.
- App Roles
- Now click on App Roles > + Create app role
- . Display name: api1-ReadonlyRole
- Allowed member types: User/Groups
- Value: api1-ReadonlyRole
- Description: api1-ReadonlyRole
- Do you wan to enable this app role? Checked
- Click Apply
- We will add a client application later
- Now click on App Roles > + Create app role
- Manifest
-
In the Manifest change the following value
"accessTokenAcceptedVersion": null
-
To this value
"accessTokenAcceptedVersion": 2
-
Click Save
-
Now let's create the app registration for the Postman client.
- Navigate to the Azure Portal > Azure Active Directory > App Registrations > + New Registration
- Name: apiPostMan
- Account Type: Accounts in the organization directory only
- Redirect URI: leave blank.
- Then click Register
- Authentication
- Click on + Add a Platform > Single-page application
- Enter the redirect URI for the Application.
- Select the tokend you would like to be issued by the authoration endpoint:
- Access tokens checked
- ID tokens checked - we're going to use implicit flow
- who can use this application or access vi API?
- Accounts in this organizational directory only (single tenant)
- Token configuration
- Here you can configure what claims you want to see in the token. As an example I added the auth_time and tenant_ctry claims to the Access Token.
- API Permmissions
- Click on + Add a permission > My APIs > api1
- Selected Delegated permissions
- Select api1.Read
- Click Add permissions
- Click on Grant admin constent and Yes on the confirmation
- Click on + Add a permission > My APIs > api1
- Manifest
-
In the Manifest change the following value
"accessTokenAcceptedVersion": null
-
To this value
"accessTokenAcceptedVersion": 2
-
Click Save
-
- Naviate to Azure AD > App Registrations > api2a > Expose API
- Click on + Add a client application and Enter the Application (client) ID of the api2 app registration (this can be found in the Overview section of the registration)
- Authorized scopes: Check the api:///api2a.Read
- Click Add application
- Naviate to Azure AD > App Registrations > api2b > Expose API
- Click on + Add a client application and Enter the Application (client) ID of the api2 app registration (this can be found in the Overview section of the registration)
- Authorized scopes: Check the api:///api2b.Read
- Click Add application
- Naviate to Azure AD > App Registrations > api2 > Expose API
- Click on + Add a client application and Enter the Application (client) ID of the api1 app registration (this can be found in the Overview section of the registration)
- Authorized scopes: Check the api:///api2.Read
- Click Add application
- Naviate to Azure AD > App Registrations > api1 > Expose API
- Click on + Add a client application and Enter the Application (client) ID of the apiPostMan app registration (this can be found in the Overview section of the registration)
- Authorized scopes: Check the api:///api1.Read
- Click Add application
- Navigate to Azure AD > Enterprise applications > api2a
- Click on Users and Groups > + Add user/group
- Add the users or groups you want to add
- Select a role (api2a-ReadonlyRole should be the only one)
- Navigate to Azure AD > Enterprise applications > api2b
- Click on Users and Groups > + Add user/group
- Add the users or groups you want to add
- Select a role (api2b-ReadonlyRole should be the only one)
- Navigate to Azure AD > Enterprise applications > api2
- Click on Users and Groups > + Add user/group
- Add the users or groups you want to add
- Select a role (api2-ReadonlyRole should be the only one)
- Navigate to Azure AD > Enterprise applications > api1
- Click on Users and Groups > + Add user/group
- Add the users or groups you want to add
- Select a role (api1-ReadonlyRole should be the only one)
- Open the solution in Visual Studio
- In the solution navigate to the api1 project > open the appsettings.json file
- Update the AzureAD Secition and DownstreamApi Section
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "<your domain name>",
"TenantId": "<your domain tenant Id>",
"ClientId": "< your api1 application (client) ID",
"Scopes": "api1.Read",
"CallbackPath": "/signin-oidc",
"ClientSecret": "< your secret if you configured one>",
"ClientCertificates": []
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"DownstreamApi": {
"Scopes": "api://<api2 application (client id)>/api2.Read",
"BaseUrl": "https://localhost:44368/api"
}
}- In the solution navigate to the api2 project > open the appsettings.json file
- Update the AzureAD Secition and DownstreamApi Section
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "<your domain name>",
"TenantId": "<your domain tenant Id>",
"ClientId": "< your api1 application (client) ID>",
"Scopes": "api2.Read",
"CallbackPath": "/signin-oidc",
"ClientSecret": "< your secret if you configured one>",
"ClientCertificates": []
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"DownstreamApi2a": {
"Scopes": "api://<api2a application (client id)>/api2a.Read",
"BaseUrl": "https://localhost:44355/api"
},
"DownstreamApi2b": {
"Scopes": "api://<api2b application (client id)>/api2b.Read",
"BaseUrl": "https://localhost:44394/api"
}
}- In the solution navigate to the api2a project > open the appsettings.json file
- Update the AzureAD Secition
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "<your domain name>",
"TenantId": "<your domain tenant Id>",
"ClientId": "< your api1 application (client) ID>",
"Scopes": "api2a.Read",
"CallbackPath": "/signin-oidc"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}- In the solution navigate to the api2b project > open the appsettings.json file
- Update the AzureAD Secition
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "<your domain name>",
"TenantId": "<your domain tenant Id>",
"ClientId": "< your api1 application (client) ID>",
"Scopes": "api2b.Read",
"CallbackPath": "/signin-oidc"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}- Ensure the solution is configured to run all the API Project
- Right Click on the Solution > Properties > Startup Project
- Select Multiple startup project and set all of them to run except models

- Click OK
- In the tool bar Click on Start

- You should see all 4 APIs start

Set breakpoints in each of the projects so we can look at the tokens.
- In the api1 project open Controllers/ProfileProductsController.cs and set a breakpoint on line 30.

- In the api2 project open Controllers/OrchestratorController.cs and set a breakpoint on line 31

- In the api2a project open Controllers/ProfileController.cs and set a breakpoint on line 41.

- In the api2b project open Controllers/ProfileController.cs and set a breakpoint on line 37

- Create a Collection in Postman named API Calls
- Add a new request to the collcation named API1
- Type GET
- Request Url: The URL to your API1 (e.g. https://localhost:44333/api/ProfileProducts/GetProfileProducts/1) .
- Click on the Authorization Tab and set the following values:
- Type: Oauth 2.0
- Ad authorization data to: Request Headers
- Current Token
- Access Token: token from authenticating
- Configure New Token:
- Grant Type: Implicit
- Callback URL: https://oauth.pstmn.io/v1/callback
- Auth URL: Get this from the apiPostMan App Registration Endpoints
- Client ID: Application (client) ID for the apiPostMan app registration
- Scope: api://<api1 application (client) ID>/api1.Read
- Client Authentication: Send as Basic Auth header
- Click on Get New Access Token
- This will prompt you to authenticate against your AAD tenant. Ensure you login with a user that assigned the App Role Permissions.
- Click on Use Token
- Now that Postman is configured to call your API and you have avalid token. Click Send.

- The api1 project should break.
- Add a watch for HttpContext.Request.Headers.Authorization

- Right click on the watch and Copy Value. Open a browser and navigate to https://jwt.ms and past the value into the test box. You will have to remove '{Bearer ' from the beginning of the value and '}' from the end of the value
- Inspect the token for roles, scopes (scp), and claims (auth_time, tenant_ctry).

- In Visual Studio click Continue to keep inspecting the token in each of the APIs that are called hitting the breakpoints.
- Once you have gone through all the breakpoints and continued the applicaiton. You should see the data results in Postman.

















