Azure

Calling Web API to Web API without User Interaction by using Azure Managed Identity

Introduction

In the world of Azure, there are two commonly used methods to authenticate and authorize Web APIs to access other Web APIs without any user interaction needed.

  • Managed Identity (requires Admin consent)
  • Client Credentials Flow (requires Admin consent) – We will discuss this in the next post.

Azure Managed Identity

Azure Managed Identity offers a seamless and automatic way to authenticate applications or services within Azure. With Managed Identity, Azure takes care of managing the credentials, eliminating the need for manual storage of secrets or client credentials. When a Web API with Managed Identity needs to call another Web API, it can use its Managed Identity to authenticate and authorize the request without explicitly providing credentials.

To configure and execute this service, you will need the following:

  • Azure Active Directory service
    • Create an App (SPN) registration
  • Two Azure Web App services – Both Web APIs must be deployed for this setup to work. It will not work locally or on your machine.
  • Admin consent is required on Azure PowerShell to execute the script
  • Two .NET Core Web API projects.

Follow these steps:

  1. Create two different Azure App services, WebAPI1 and WebAPI2, in the Azure portal.
  2. Go to WebAPI1, select Identity under the Settings section, and enable System Assigned Managed Identity. Copy the Object (Principal) ID.
  3. To create an App registration, follow these steps:
    • Navigate to the Azure Active Directory service.
    • Under the “Manage” section, select “App registrations.”
    • Click on the “New registration” button.
    • Provide a meaningful name for the app registration, such as “WebAPI-mi”.
    • Choose “Accounts in this organizational directory only” (Default Directory only – Single tenant) as the account type.
    • Click the “Register” button to create the app registration.
  4. Create an App role in the App Registration:
    • Go to App Roles under the Manage section, click on “Create app roles” and provide the display name and value as “app_role_access_mi” and a description. Make sure to enable the state.Calling Web API to Web API without User Interaction by using Azure Managed Identity
  5. Execute the PowerShell script below, either in the Azure portal, Azure CLI, or through Windows PowerShell. Make sure to grant Admin consent and install the required modules as mentioned in the comments.
    • If you want to add the app role for Microsoft.Graph, then execute the script given in the above link.
    • If you want to add a custom app role for your WebAPI2, then execute the below script using PowerShell.
      # Install the module.
      # Install-Module Microsoft.Graph -Scope CurrentUser
      
      # The tenant ID - replace from Azure active directory overview page
      $TenantId = "111111111111111111111111111111111"  
      
      # The name of your web API name and the resource group name, which has a managed identity.
      $webAppName = "WebAPI1" 
      # Resource group of WebAPIs
      $resourceGroupName = "WebAPI-RG"   
      
      # The name of the app role that the managed identity should be assigned to.
      $appRoleName = "app_role_access_mi"
      
      # Get the web app's managed identity's object ID.
      Connect-AzAccount -Tenant $TenantId
      $managedIdentityObjectId = (Get-AzWebApp -ResourceGroupName $resourceGroupName -Name $webAppName).identity.principalid
      
      # Get Microsoft Graph app's service principal and app role.
      $serverApplicationName = "WebAPI2"
      $serverServicePrincipal = (Get-MgServicePrincipal -Filter "DisplayName eq '$serverApplicationName'")
      $serverServicePrincipalObjectId = $serverServicePrincipal.Id
      
      $appRoleId = ($serverServicePrincipal.AppRoles | Where-Object {$_.Value -eq $appRoleName }).Id
      
      # Assign the managed identity access to the app role.
      New-MgServicePrincipalAppRoleAssignment `
          -ServicePrincipalId $managedIdentityObjectId `
          -PrincipalId $managedIdentityObjectId `
          -ResourceId $serverServicePrincipalObjectId `
          -AppRoleId $appRoleId
      
  6. After executing the above script, verify that it has been registered in the AAD. Go to the enterprise application of Azure AD and search for the Object (Principal) ID from step 2. Select the enterprise app and go to the security Permissions to verify.
    Calling Web API to Web API without User Interaction by using Azure Managed Identity

  7. In the WebAPI1 using Asp.NET Core 6.0, copy and paste the below snippet in your method to call WebAPI2. Make sure to copy and paste the ClientID of the WebAPI-mi app registration from Step 3.
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Identity.Web;
    using Azure.Core;
    using Azure.Identity;
    using System.Net.Http.Headers;
    
    class YourController
    {
        [HttpGet]
        public async Task<ActionResult> CallWebAPI2()
        {
            // Create an instance of DefaultAzureCredential using the client ID or object ID of your Web API's managed identity.
            var credential = new DefaultAzureCredential();
    
            // Create an instance of HttpClient.
            var httpClient = new HttpClient();
    
            // Authenticate the HttpClient instance using the credential.
            // Copy and paste the Application (Client ID) of WebAPI-mi app registration
            var accessToken = await credential.GetTokenAsync(new Azure.Core.TokenRequestContext(new[] { "api://XXXXXXXX-0000-0000-0000-XXXXXXXXXXXX/.default" }));
            httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken.Token);
    
            // Make requests to the target Web API.
            // The actual request to the secured "integration" API
            var result = await httpClient.GetStringAsync("https://WebAPI2.azurewebsites.net/WeatherForecast");
    
            return Ok($"Response: {result}" + "Token :" + accessToken.Token);
        }
    }
    
  8. In WebAPI2, copy and paste the below code in both the AppSettings.Json and Program.cs files.

    Appsettings.json 
    
    {  
      "AzureAd" : { 
        "Instance" :  "https://login.microsoftonline.com/",
        "Domain" : "yourdomain.onmicrosoft.com",  //It comes from an overview page of Azure Active Directory
        "TenantId" : "XXXXXXXX-0000-0000-0000-XXXXXXXXXXXX",  //It comes from an overview page of Azure Active Directory
        "ClientId" :  "XXXXXXXX-0000-0000-0000-XXXXXXXXXXXX"  //Copy and paste the Application (Client ID) of WebAPI-mi app registration
        },
      "Logging": {
            "LogLevel": {
                "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
            }
        },
      "AllowedHosts": "*"
    }
    //Program.cs file
    
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.AspNetCore.Authentication.JwtBearer;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Identity.Web;
    
    var builder = WebApplication.CreateBuilder(args);
    
     // Your existing code here
            
     // Add authentication services
     builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
            
     // Your existing code here
            
     // Configure the HTTP request pipeline
     app.UseAuthentication();
     app.UseAuthorization();
            
     // Your existing code here
            
     // Start the application
     app.Run();
    
    
    
    // Create the controller with the name WeatherForecastController.cs and the below snippet. Add the [Authorize] attribute for authorization
    
    [Authorize]
    [ApiController]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };
    
        private readonly ILogger<WeatherForecastController> _logger;
    
        public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }
    
        [HttpGet(Name = "GetWeatherForecast")]
        public IEnumerable<WeatherForecast> Get()
        {
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }
    
    // Add this code in the WeatherForeCast.cs file
    public class WeatherForecast
    {
        public DateTime Date { get; set; }
        public int TemperatureC { get; set; }
        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
        public string? Summary { get; set; }
    }

    Deploy each solution in the App Service of WebAPI1 and WebAPI2. Execute the CallWebAPI2 method in WebAPI1, and you will receive a response as shown below.
    Calling Web API to Web API without User Interaction by using Azure Managed Identity

  9. You can copy and paste the token into jwt to deserialize it and see the App role assigned to the token for authorization in WebAPI2.
    Calling Web API to Web API without User Interaction by using Azure Managed Identity

This is how you can authenticate and authorize API to API communication using Managed Identity. Don’t forget to visit Skrots to explore similar services and learn more about how we can assist you. You can also check out all the services we provide at https://skrots.com/services. Thank you!

Show More

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button