Blazor  

Securing a Blazor Applications with Azure Managed Identity and API Management

Introduction

Organizations frequently deploy web applications that need to communicate with backend APIs securely. A common challenge arises when multiple applications are hosted on the same infrastructure, such as an Internet Information Services (IIS) server on an Azure Virtual Machine. Without proper security controls, any application on that server could potentially access backend APIs, creating security vulnerabilities and compliance concerns.

This article presents a comprehensive solution for securing a Blazor .NET 8 web application that calls backend APIs through Azure API Management (APIM). The solution leverages Azure Managed Identity to ensure that only the authorized application can access the backend API.

This is an extension of my previous article, where I wrote about securing Azure API Management with the Zero Trust Architecture and tested it using VisualStudio credentials.

Business Scenario

Consider a scenario where an organization has deployed a Blazor web application on an Azure Virtual Machine running IIS. The application needs to call a Weather API hosted behind Azure API Management. The security requirements include:

  • Only the Blazor application should be able to call the backend API

  • No credentials or secrets should be stored in the application configuration

  • The solution should work seamlessly in production without manual token management

  • Access should be auditable and easily revocable

Traditional approaches to API security often involve:

  • Storing API keys or client secrets in configuration files or in the Key Vault

  • Managing certificate lifecycles

These approaches introduce security risks and operational overhead. Managed Identity eliminates these concerns by allowing Azure resources to authenticate with services that support Azure Active Directory without requiring credentials in code.

The Demo solution consists of the following components:

1. Blazor .NET 8 Client Application

   A server-side Blazor application that provides an interactive user interface and makes authenticated calls to the backend API.

2. Azure Virtual Machine with IIS

   The hosting environment for the Blazor application is configured with a User-Assigned Managed Identity.

3. User-Assigned Managed Identity

   An Azure resource that provides an identity for the application to use when authenticating to Azure services.

4. Microsoft Entra ID (Azure Active Directory)

   The identity provider that issues tokens and manages application registrations and permissions.

5. Azure API Management

   The API gateway that validates JWT tokens and enforces access policies before routing requests to the backend.

6. Backend Web API

   The protected API that serves weather forecast data is registered in Entra ID with defined app roles.

The authentication flow follows these steps:

  • Step 1: The Blazor application starts on the Azure VM

  • Step 2: When the application needs to call the backend API, it requests a token from Entra ID using the Managed Identity

  • Step 3: Entra ID validates the Managed Identity and issues a JWT token with the appropriate claims and roles

  • Step 4: The application sends the API request to APIM with the JWT token in the Authorization header

  • Step 5: APIM validates the JWT token, checking the issuer, audience, and required claims

  • Step 6: If validation succeeds, APIM forwards the request to the backend API

  • Step 7: The backend API processes the request and returns the response

Step-by-Step Implementation

Step 1: Create the Backend API App Registration

Please refer to my last article on Securing Azure API Management with DefaultAzureCredential and Zero Trust Architecture, where I gave step-by-step instructions on registering the MS Entra ID application for the Backend API

Step 2: Create the User-Assigned Managed Identity

1. Navigate to the Azure Portal

2. Search for Managed Identities and click Create

3. Enter the following details:

   Subscription: Your subscription

   Resource group: Your resource group

   Region: Same region as your VM

   Name: give some name (example: mi-blazor-apim-client)

4. Click Review + create, then Create

5. Note the Client ID: In my case, it is 29fb906c-820b-4440-acd1-6baab44bfd42

User assigned

Step 3: Assign the App Role to the Managed Identity

Grant the Managed Identity permission to access the backend API by running the following PowerShell commands in Azure Cloud Shell:

    connect-AzAccount

    $managedIdentityClientId = "{user-assigned managed identity app id}"
    $backendApiAppId = "{API App Id}"

    $miSP = Get-AzADServicePrincipal -Filter "appId eq '$managedIdentityClientId'"
    $apiSP = Get-AzADServicePrincipal -Filter "appId eq '$backendApiAppId'"

    New-AzADServicePrincipalAppRoleAssignment `
        -ServicePrincipalId $miSP.Id `
        -ResourceId $apiSP.Id `
        -AppRoleId "{your app role id}"
App Role Id

You can get the app role id from App registration -> select the API app-> App roles as shown in the above figure

Step 4: Assign the Managed Identity to the Azure VM

  1. Navigate to your Virtual Machine in the Azure Portal

  2. Go to Identity in the left menu

  3. Select the User assigned tab

  4. Click Add

  5. Select mi-blazor-apim-client

  6. Click Add

Managed Identity - VM

Step 5: Configure the Blazor Application

Update the appsettings.json file with the following configuration:

    {
      "AzureAd": {
        "TenantId": "{your tenant id}",
        "ClientId": "{Managed idenity client id}",
        "UseManagedIdentity": true,
      },
      "BackendAPI": {
        "BaseUrl": "https://apim-pi-tracking.azure-api.net",
        "Scopes": "api://{your api app client id}/.default"
      }
    }

Step 6: Implement the Token Acquisition Code

The Program.cs file configures the application to use Managed Identity:

    if (useManagedIdentity)
    {
        credential = new ManagedIdentityCredential(clientId);
        authMethod = $"Managed Identity (Client ID: {clientId})";
        Console.WriteLine($"Using Managed Identity with Client ID: {clientId}");
    }

The ApiService.cs file acquires tokens and calls the API:

    var apiScope = _configuration["BackendAPI:Scopes"];
    var tokenRequestContext = new TokenRequestContext(new[] { apiScope });
    var accessToken = await _credential.GetTokenAsync(tokenRequestContext, CancellationToken.None);

    httpClient.DefaultRequestHeaders.Authorization = 
        new AuthenticationHeaderValue("Bearer", accessToken.Token);

    var response = await httpClient.GetAsync("/weather/forecast");

Get the complete source code from my GitHub Repository

Step 7: Configure APIM JWT Validation Policy

Add the following inbound policy to your API in Azure API Management to validate tokens and restrict access to only your Managed Identity:

    <inbound>
        <base />
        <validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Token validation failed.">
            <openid-config url="https://login.microsoftonline.com/{your tenant id}/v2.0/.well-known/openid-configuration" />
            <audiences>
                <audience>api://{your api Entra app client id}</audience>
            </audiences>
            <issuers>
                <issuer>https://sts.windows.net/{your tenant id}/</issuer>
            </issuers>
            <required-claims>
                <claim name="roles" match="any">
                    <value>weather.read</value>
                </claim>
            </required-claims>
        </validate-jwt>
    </inbound>

 Step 8: Configure and deploy the Blazor client application in Azure VM IIS

Summary:

This implementation demonstrates a production-ready pattern for securing Blazor applications using Azure Managed Identity and API Management. By combining these Azure services, organizations can achieve enterprise-grade security without the operational burden of traditional credential management.

The key components of this solution include:

  •     User-Assigned Managed Identity for application authentication

  •     App Roles in Entra ID for fine-grained access control

  •     JWT validation in APIM for token verification and policy enforcement

  •     DefaultAzureCredential in .NET for seamless local development and production

This pattern can be extended to other Azure services and scenarios, including Azure Functions, App Services, Container Apps, and any service that supports Managed Identity authentication.