Adding Microsoft Identity Platform To An Existing App

You can do this when creating a new App from Visual Studio by selecting Authentication type -> Microsoft identity platform. This will configure the template for you and even register the App if the account you authenticate to Visual Studio with has privilege.

In my case, I needed to add Microsoft identity platform to an existing ASP.NET Core MVC app. The Visual Studio template handles this automatically, but I had to wire it in manually. This post is the exact sequence I followed.

1. Register the app with Entra

In Microsoft Entra admin center, go to App registrations and open your app (or create one). Under Authentication, add your redirect URI(s) under Web platform:

1
2
3
https://localhost:5001/signin-oidc
https://your-uat-host/signin-oidc
https://your-prod-host/signin-oidc

Record the Application (client) ID and Directory (tenant) ID—you’ll need these in appsettings.json.

Docs: Register an appAdd redirect URI

2. Install the identity packages

1
2
3
dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect --version 8.0.15
dotnet add package Microsoft.Identity.Web --version 3.8.2
dotnet add package Microsoft.Identity.Web.UI --version 3.8.2

Docs: Microsoft.Identity.Web

3. Configure authentication in Program.cs

1
2
3
4
5
6
7
8
9
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;

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

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

This sets up OpenID Connect with AddMicrosoftIdentityWebApp(...) and adds the built-in Microsoft Identity UI (which provides the Account controller).

Docs: AddMicrosoftIdentityWebApp

4. Wire up the middleware in Program.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");

app.MapRazorPages(); // Required for Microsoft Identity UI

The order matters: UseAuthentication() must come before UseAuthorization(), and both must come after UseRouting().

Docs: Middleware order

5. Add AzureAd config to appsettings.json

1
2
3
4
5
6
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "<tenant-id-from-step-1>",
"ClientId": "<client-id-from-step-1>",
"CallbackPath": "/signin-oidc"
}

Make sure CallbackPath matches your redirect URI path from the app registration.

Docs: Configure appsettings.json

Create /Views/Shared/_LoginPartial.cshtml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<ul class="navbar-nav">
@if (User.Identity?.IsAuthenticated == true)
{
<span class="navbar-text">Hello @User.Identity?.Name!</span>
<li class="nav-item">
<a class="nav-link" asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignOut">Sign out</a>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link" asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignIn">Sign in</a>
</li>
}
</ul>

Then add it to /Views/Shared/_Layout.cshtml:

1
<partial name="_LoginPartial" />

The MicrosoftIdentity area and Account controller are built in to Microsoft.Identity.Web.UI.

7. Protect your endpoints

Add [Authorize] to controllers/actions you want to protect:

1
2
3
4
5
[Authorize]
public class HomeController : Controller
{
public IActionResult Index() => View();
}

Or enforce it globally in Program.cs (then use [AllowAnonymous] where needed):

1
2
3
4
5
6
7
builder.Services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});

Docs: Simple authorization

8. If you get AADSTS50011 (redirect URI mismatch)

This error means your app is sending a different redirect URI than what’s registered. Check:

  1. Scheme matches (http vs https)
  2. Host matches exactly
  3. Path is /signin-oidc
  4. It’s registered in app registration → Authentication → Web

Docs: Troubleshoot AADSTS50011

9. If hosted behind Azure Container Apps or reverse proxy

When a reverse proxy terminates TLS, your app needs to read forwarded headers to know the request is really HTTPS.

In Program.cs:

1
2
3
4
5
6
7
8
9
10
11
using Microsoft.AspNetCore.HttpOverrides;

builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});

app.UseForwardedHeaders(); // Call this early, before UseHttpsRedirection()

This is especially important for OIDC redirect URIs—if your app thinks the request is http instead of https, the redirect URI won’t match what’s registered.

Docs: Configure for proxy/load balancer