---
title: "How Do I Secure an ASP.NET Core API with Microsoft Entra ID on Azure?"  
description: "How should an ASP.NET Core API hosted on Azure validate Entra ID tokens and distinguish delegated user access from service-to-service permissions? This question covers app registration, scopes, and token checks."  
author: "Manish Sharma"  
published: 2026-10-14  
updated: 2026-10-14  
canonical: https://answers.mindstick.com/blog/688/how-do-i-secure-an-asp-net-core-api-with-microsoft-entra-id-on-azure  
category: "Azure with .NET Core"  
tags: ["azure", ".NET Core", "Microsoft Entra ID", "ASP.NET Core", "API Security"]  
reading_time: 4 minutes  

---

# How Do I Secure an ASP.NET Core API with Microsoft Entra ID on Azure?

I have an [ASP.NET Core API](https://www.mindstick.com/forum/157445/how-to-use-aspnet-core-apis-in-the-class-library) hosted on Azure and want callers to sign in with Microsoft Entra ID. I understand that the API needs to validate a bearer token, but I’m unsure which parts belong in the app registration, which belong in the .NET code, and how to make sure a token is actually meant for my API.

A useful way to think about it: Entra ID issues the token, and your API checks that token before serving protected endpoints. The API does not need to handle passwords or ask the caller to send credentials directly.

## Set up the API registration first

In the Azure portal, register the API as an application in Microsoft Entra ID. Under **Expose an API**, set an Application ID URI and add a delegated scope, for example `access_as_user`. A client application can then request that permission when it needs to call your API on behalf of a signed-in user.

Record the tenant ID and application (client) ID for the API registration. These identify the authority and the API; they are not passwords. The API’s registration is different from the registration for a web, mobile, or command-line client that obtains tokens.

## Validate tokens in ASP.NET Core

The `Microsoft.Identity.Web` package wires ASP.NET Core authentication to Entra ID. In a controller-based app, the important details are registering bearer authentication, enabling authorization, and putting the middleware in the right order. Here’s a compact example for an API that requires the `access_as_user` scope on its orders endpoint:

```cs
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

// Validate incoming bearer tokens using the API's Entra ID settings.
builder.Services
    .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

// Register authorization so endpoint attributes and scope checks are applied.
builder.Services.AddAuthorization();

var app = builder.Build();

app.UseHttpsRedirection();

// Authentication must run before authorization can inspect the caller.
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();
app.Run();

[ApiController]
[Route("api/orders")]
[Authorize]
public sealed class OrdersController : ControllerBase
{
    [HttpGet]
    [RequiredScope("access_as_user")]
    public IActionResult GetOrders()
    {
        // Return data only after the token passes authentication and scope checks.
        return Ok(new[] { "order-1001", "order-1002" });
    }
}
```

The `AzureAd` section in configuration should contain the tenant ID, client ID, and the API’s expected audience, along with the Entra ID instance. The exact audience value depends on how the API registration is configured, so check it against the API’s Application ID URI and the token’s `aud` claim. A mismatch commonly means the client requested a token for a different resource.

Keep environment-specific settings in Azure App Service configuration or another configuration provider. Tenant and application IDs are identifiers, not secrets. An API validating tokens this way generally does not need a client secret just to validate them.

## Authentication is not the same as permission

A valid token proves that Entra ID issued it and that it is intended for the API. It does not automatically mean the caller may perform every operation. `[Authorize]` requires an authenticated caller; `[RequiredScope]` checks that a delegated token includes the scope the endpoint expects. You can also add role-based checks when access depends on an application role rather than a delegated scope.

For a user-facing client, request the API’s delegated permission and obtain a token for this API—not a token for Microsoft Graph or another service. The client sends that token in the `Authorization: Bearer` header. The API should reject tokens with the wrong audience, tenant, signature, or expiry rather than trying to interpret them as credentials.

## What changes for service-to-service calls?

A daemon or backend service may call the API without a signed-in user. That is a different flow: configure an application permission or app role, grant the required admin consent, and have the calling service request an app-only token. Don’t rely on a delegated scope such as `access_as_user` for this case. The API should authorize the app identity and the permissions it was granted.

When the API itself calls Azure services, that is another separate identity boundary. Use a managed identity for those outbound calls where the service supports it. Managed identity helps the API access resources such as Key Vault or Storage; it does not replace validating incoming user or client tokens.

When testing, inspect a token issued specifically for your API and verify its audience and permission claims. If authentication succeeds but a protected action returns forbidden, check the scope or app role assignment. If the token is rejected before authorization, start with the issuer, audience, tenant, and token expiry.

---

Original Source: https://answers.mindstick.com/blog/688/how-do-i-secure-an-asp-net-core-api-with-microsoft-entra-id-on-azure

Copyright © MindStick Software Pvt. Ltd. This Markdown version is provided for developers, AI systems, and offline reading.
