Skip to content

[Entra ID] Add Razor Pages-specific authentication integration #3852

Description

@danroth27

Summary

Add Razor Pages-specific Entra ID integration to the scaffolder.

The current scaffolder accepts applications that use Razor Pages but applies Blazor-oriented code and templates. It reports success and leaves a normal Razor Pages project unable to build.

Razor Pages support must compose with MVC, Razor components, APIs, SignalR, and other ASP.NET Core capabilities in the same application.

Related: #2890

Steps to reproduce

dotnet new webapp -n EntraRazorPages `
    --framework net11.0

dotnet scaffold aspnet entra-id `
    --project .\EntraRazorPages\EntraRazorPages.csproj `
    --username <tenant-user> `
    --tenantId <tenant> `
    --use-existing-application false

dotnet build .\EntraRazorPages\EntraRazorPages.csproj

Current behavior

The scaffolder applies the Blazor server registrations:

builder.Services.AddAuthentication(
        OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(
        builder.Configuration.GetSection("AzureAd"));

builder.Services.AddCascadingAuthenticationState();

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = options.DefaultPolicy;
});

It generates:

Components/Layout/LoginOrLogout.razor

A normal Razor Pages application doesn't contain the Blazor imports expected by this component, so the project fails to build:

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 project builds and challenges users through Entra, but Razor Pages integration remains incomplete:

  • Microsoft.Identity.Web.UI isn't added.
  • AddMicrosoftIdentityUI() isn't called.
  • MapControllers() isn't added for the Microsoft Identity UI controller endpoints.
  • No Pages/Shared/_LoginPartial.cshtml is generated.
  • The Razor Pages layout has no sign-in or sign-out UI.
  • AddCascadingAuthenticationState() is unnecessary unless the application also uses Razor components.

Expected behavior

When the application has Razor Pages capabilities, add Razor Pages-specific authentication integration in addition to any integration required by its other capabilities.

Generated packages

Add:

<PackageReference Include="Microsoft.Identity.Web" />
<PackageReference Include="Microsoft.Identity.Web.UI" />

Package additions must remain idempotent when MVC or another feature needs the same package.

Generated services

Configure authentication once for the host:

builder.Services.AddAuthentication(
        OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(
        builder.Configuration.GetSection("AzureAd"));

Make pages private by default and add Microsoft Identity UI:

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = options.DefaultPolicy;
});

builder.Services.AddRazorPages()
    .AddMicrosoftIdentityUI();

If AddRazorPages() already exists, modify the existing service chain instead of adding a duplicate.

Only add AddCascadingAuthenticationState() when Razor components are also detected.

Generated endpoints

Preserve the existing page mapping and add controller endpoints required by Microsoft Identity UI:

app.MapRazorPages();
app.MapControllers();

Don't duplicate endpoint mappings already present for MVC or APIs.

Generated Razor Pages UI

Generate:

Pages/Shared/_LoginPartial.cshtml

with working Microsoft Identity UI sign-in and sign-out links.

Reference it from:

Pages/Shared/_Layout.cshtml

using:

<partial name="_LoginPartial" />

Don't generate a Blazor .razor login component unless the application also contains a Razor component UI.

Capability detection and composition

Use independent capability detection rather than a mutually exclusive project-type classification.

Razor Pages can be detected from service and endpoint usage such as:

builder.Services.AddRazorPages();
app.MapRazorPages();

The detector should distinguish Razor Pages from Razor components:

builder.Services.AddRazorComponents();
app.MapRazorComponents<App>();

It should also inspect the Razor SDK/project metadata and existing Pages files when registrations have been moved into extension methods.

Capability combinations should compose:

  • Razor Pages + MVC: add one shared authentication registration, Microsoft Identity UI once, and appropriate login UI for each active layout.
  • Razor Pages + Blazor: add Razor Pages UI plus Blazor authentication-state and routing integration.
  • Razor Pages + APIs: retain cookie/OIDC behavior for pages and apply API-specific bearer authorization to API endpoints.
  • Razor Pages + SignalR: preserve page authentication while applying SignalR-specific authorization where needed.

All modifications must be idempotent.

If the scaffolder can't identify a safe service-registration or layout insertion point, it should fail before tenant mutation and explain the ambiguous integration point.

Template parity

The Razor Pages integration should preserve the Microsoft Identity Platform behavior currently provided by:

dotnet new webapp --auth SingleOrg

Graph and downstream API options are tracked by #3847.

Relevant areas

  • ValidateEntraIdStep
  • ASP.NET Core capability detection/model
  • Razor Pages-specific package and code-modification steps
  • Razor Pages _LoginPartial template
  • Shared app-registration provisioning

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions