Summary
Add Entra ID support for ASP.NET Core Web APIs, including controller-based and Minimal API endpoints.
The current scaffolder accepts Web API projects but applies web-app OpenID Connect and Blazor-specific code. It reports success and leaves the generated API unable to build. If the Blazor artifact is manually removed, unauthenticated API requests receive browser login redirects instead of JWT bearer challenges.
Web API support must compose with MVC, Razor Pages, Razor components, SignalR, and other capabilities hosted by the same ASP.NET Core application.
Related: #2890
Steps to reproduce
Minimal API
dotnet new webapi -n EntraMinimalApi `
--framework net11.0
dotnet scaffold aspnet entra-id `
--project .\EntraMinimalApi\EntraMinimalApi.csproj `
--username <tenant-user> `
--tenantId <tenant> `
--use-existing-application false
dotnet build .\EntraMinimalApi\EntraMinimalApi.csproj
Controller API
dotnet new webapi -n EntraControllerApi `
--framework net11.0 `
--use-controllers
dotnet scaffold aspnet entra-id `
--project .\EntraControllerApi\EntraControllerApi.csproj `
--username <tenant-user> `
--tenantId <tenant> `
--use-existing-application false
dotnet build .\EntraControllerApi\EntraControllerApi.csproj
Current behavior
The scaffolder configures both API shapes as interactive web applications:
builder.Services.AddAuthentication(
OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(
builder.Configuration.GetSection("AzureAd"));
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = options.DefaultPolicy;
});
It also generates:
Components/Layout/LoginOrLogout.razor
Both Web API projects fail to build because the generated Blazor component depends on imports and types that aren't present:
warning RZ10012: Found markup element with unexpected name
'AuthorizeView'.
error CS0246: The type or namespace name
'LocationChangedEventArgs' could not be found.
If the generated Components directory is manually removed, the APIs build but still have incorrect authentication behavior:
AddMicrosoftIdentityWebApp configures cookie/OIDC web sign-in instead of bearer-token validation.
AddMicrosoftIdentityWebApi isn't generated.
- The default authentication scheme is OpenID Connect instead of JWT bearer.
- No delegated scope or application-role validation is generated.
- Minimal API endpoints don't call
RequireAuthorization or validate an accepted scope.
- API controllers don't receive
[Authorize] or [RequiredScope].
- A request without a bearer token receives an HTTP
302 redirect to login.microsoftonline.com instead of an API 401 response.
- A password credential and Web redirect URIs are created even though a protected API doesn't need interactive sign-in.
Expected behavior
When API capabilities are detected, generate protected Web API integration appropriate to the endpoint style.
Pure Web API host
For an application that only hosts APIs, configure JWT bearer authentication:
builder.Services.AddAuthentication(
JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(
builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization();
Don't generate:
AddMicrosoftIdentityWebApp(...)
AddCascadingAuthenticationState()
MapLoginAndLogout()
Don't generate login/logout UI.
A protected API registration doesn't require Web redirect URIs or a client credential unless the API also acts as a confidential client to call another API.
Minimal API endpoints
Protect selected API endpoints and validate the required delegated scope:
var requiredScope =
app.Configuration["AzureAd:Scopes"];
app.MapGet("/weatherforecast", (HttpContext context) =>
{
context.VerifyUserHasAnyAcceptedScope(requiredScope);
// ...
})
.RequireAuthorization();
An equivalent authorization policy or RequireScope extension is also appropriate.
The scaffolder should allow the user to select or configure the exposed scope, with a default such as:
Controller APIs
Generate controller authorization:
[Authorize]
[RequiredScope(
RequiredScopesConfigurationKey = "AzureAd:Scopes")]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
// ...
}
Prefer a convention, global filter, or policy when protecting all API controllers, rather than editing every controller independently.
App-registration provisioning
For a new protected API registration, the scaffolder should:
-
Create an Application ID URI, such as api://<client-id>.
-
Expose a delegated scope such as access_as_user.
-
Support defining application roles for app-only callers.
-
Avoid enabling implicit grants.
-
Avoid adding Web redirect URIs unless the same registration also represents an interactive web client.
-
Avoid creating a client credential unless the API calls another API.
-
Generate matching configuration:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "<tenant-id>",
"ClientId": "<api-client-id>",
"Audience": "api://<api-client-id>",
"Scopes": "access_as_user"
}
}
Endpoints that accept application tokens should validate app roles instead of delegated scopes. Endpoints that accept both should use the corresponding Microsoft Identity Web scope-or-app-permission support.
HTTP behavior
Generated APIs should return:
401 Unauthorized for a missing or invalid token.
403 Forbidden for an authenticated token that lacks the required scope or role.
They shouldn't redirect API clients to a browser login page.
Capability detection and composition
Detect independent API capabilities instead of assigning one exclusive project type.
Possible capability model:
public sealed class AspNetAppCapabilities
{
public bool HasMvcViews { get; init; }
public bool HasRazorPages { get; init; }
public bool HasRazorComponents { get; init; }
public bool HasControllerApis { get; init; }
public bool HasMinimalApis { get; init; }
public bool HasSignalR { get; init; }
}
Controller API capabilities can be detected from:
builder.Services.AddControllers();
app.MapControllers();
plus controller semantics such as:
[ApiController]
ControllerBase
AddControllersWithViews() may host both MVC views and API controllers, so controller discovery should inspect the controllers rather than treating MVC and APIs as mutually exclusive.
Minimal API capabilities can be detected from endpoint registrations such as:
app.MapGet(...);
app.MapPost(...);
app.MapGroup(...);
In a mixed UI/API host, not every mapped endpoint is necessarily an API requiring bearer authentication. The scaffolder should identify endpoint groups that are already marked as APIs, use existing authorization metadata, or prompt the user to select which route groups/endpoints to protect.
Capability combinations should compose:
- UI + controller API: retain cookie/OIDC as the UI default and add a named JWT bearer scheme/policy for API controllers.
- UI + Minimal API: apply the API bearer policy only to selected endpoint groups.
- Blazor Web App + API/BFF endpoints: keep tokens server-side and authorize the server endpoints independently.
- API + SignalR: add the SignalR bearer-token transport handling without replacing ordinary API validation.
For a mixed host, don't globally replace the UI authentication scheme with JWT bearer. Configure named schemes or a policy scheme and apply the appropriate authorization policy to each surface.
All registrations, packages, and endpoint changes must be idempotent.
Template parity
The generated pure Web API result should preserve and modernize the Microsoft Identity Platform behavior currently provided by:
dotnet new webapi --auth SingleOrg
Graph, downstream API, and OBO support are tracked separately by #3847 or follow-up API-specific work.
Relevant areas
ValidateEntraIdStep
- ASP.NET Core capability detection/model
- Web API app-registration provisioning
- Controller API code modifications
- Minimal API code modifications
- API scope/role options and configuration
Summary
Add Entra ID support for ASP.NET Core Web APIs, including controller-based and Minimal API endpoints.
The current scaffolder accepts Web API projects but applies web-app OpenID Connect and Blazor-specific code. It reports success and leaves the generated API unable to build. If the Blazor artifact is manually removed, unauthenticated API requests receive browser login redirects instead of JWT bearer challenges.
Web API support must compose with MVC, Razor Pages, Razor components, SignalR, and other capabilities hosted by the same ASP.NET Core application.
Related: #2890
Steps to reproduce
Minimal API
Controller API
Current behavior
The scaffolder configures both API shapes as interactive web applications:
It also generates:
Both Web API projects fail to build because the generated Blazor component depends on imports and types that aren't present:
If the generated
Componentsdirectory is manually removed, the APIs build but still have incorrect authentication behavior:AddMicrosoftIdentityWebAppconfigures cookie/OIDC web sign-in instead of bearer-token validation.AddMicrosoftIdentityWebApiisn't generated.RequireAuthorizationor validate an accepted scope.[Authorize]or[RequiredScope].302redirect tologin.microsoftonline.cominstead of an API401response.Expected behavior
When API capabilities are detected, generate protected Web API integration appropriate to the endpoint style.
Pure Web API host
For an application that only hosts APIs, configure JWT bearer authentication:
Don't generate:
Don't generate login/logout UI.
A protected API registration doesn't require Web redirect URIs or a client credential unless the API also acts as a confidential client to call another API.
Minimal API endpoints
Protect selected API endpoints and validate the required delegated scope:
An equivalent authorization policy or
RequireScopeextension is also appropriate.The scaffolder should allow the user to select or configure the exposed scope, with a default such as:
Controller APIs
Generate controller authorization:
Prefer a convention, global filter, or policy when protecting all API controllers, rather than editing every controller independently.
App-registration provisioning
For a new protected API registration, the scaffolder should:
Create an Application ID URI, such as
api://<client-id>.Expose a delegated scope such as
access_as_user.Support defining application roles for app-only callers.
Avoid enabling implicit grants.
Avoid adding Web redirect URIs unless the same registration also represents an interactive web client.
Avoid creating a client credential unless the API calls another API.
Generate matching configuration:
{ "AzureAd": { "Instance": "https://login.microsoftonline.com/", "TenantId": "<tenant-id>", "ClientId": "<api-client-id>", "Audience": "api://<api-client-id>", "Scopes": "access_as_user" } }Endpoints that accept application tokens should validate app roles instead of delegated scopes. Endpoints that accept both should use the corresponding Microsoft Identity Web scope-or-app-permission support.
HTTP behavior
Generated APIs should return:
401 Unauthorizedfor a missing or invalid token.403 Forbiddenfor an authenticated token that lacks the required scope or role.They shouldn't redirect API clients to a browser login page.
Capability detection and composition
Detect independent API capabilities instead of assigning one exclusive project type.
Possible capability model:
Controller API capabilities can be detected from:
plus controller semantics such as:
AddControllersWithViews()may host both MVC views and API controllers, so controller discovery should inspect the controllers rather than treating MVC and APIs as mutually exclusive.Minimal API capabilities can be detected from endpoint registrations such as:
In a mixed UI/API host, not every mapped endpoint is necessarily an API requiring bearer authentication. The scaffolder should identify endpoint groups that are already marked as APIs, use existing authorization metadata, or prompt the user to select which route groups/endpoints to protect.
Capability combinations should compose:
For a mixed host, don't globally replace the UI authentication scheme with JWT bearer. Configure named schemes or a policy scheme and apply the appropriate authorization policy to each surface.
All registrations, packages, and endpoint changes must be idempotent.
Template parity
The generated pure Web API result should preserve and modernize the Microsoft Identity Platform behavior currently provided by:
dotnet new webapi --auth SingleOrgGraph, downstream API, and OBO support are tracked separately by #3847 or follow-up API-specific work.
Relevant areas
ValidateEntraIdStep