Azure AD vs Entra ID: Migration Guide for .NET Apps in 2026

·By Elysiate·Updated Apr 3, 2026·
azureentra idazure addotnetauthenticationmigration
·

Level: advanced · ~17 min read · Intent: informational

Audience: .NET developers, backend engineers, security engineers, solution architects

Prerequisites

  • basic familiarity with ASP.NET Core
  • general understanding of OAuth 2.0 and OpenID Connect
  • some experience with Azure or Microsoft identity integrations

Key takeaways

  • For many .NET teams, the real migration is not from one identity provider to another, but from older Azure AD-era libraries and Graph patterns to modern Entra ID, MSAL, Microsoft Identity Web, and Microsoft Graph.
  • Authentication migration should be treated as a full platform update that includes app registrations, token validation, permission design, Graph API usage, and production monitoring.
  • The safest migrations are incremental, testable, and explicit about scopes, app roles, tenant boundaries, and secure secret handling.

FAQ

Is Azure AD to Entra ID a real technical migration or mostly a rename?
The product rename itself is mostly naming, but many .NET applications still need a real migration because they use older Azure AD-era SDKs, Azure AD Graph, or older authentication patterns that should be updated to Microsoft Identity Web, MSAL, and Microsoft Graph.
Do I need to change my app registrations when moving to Entra ID?
Not always dramatically, but you should review redirect URIs, exposed scopes, app roles, supported account types, API permissions, and secret or certificate usage as part of the migration.
Should I migrate from Azure AD Graph to Microsoft Graph?
Yes. If your app still depends on Azure AD Graph-era approaches, moving to Microsoft Graph is one of the most important parts of a modern Entra migration.
What is the biggest risk during migration?
A common risk is getting sign-in working while breaking authorization, permission grants, token validation, or downstream API access because the migration focused only on login and not the full identity flow.
Can I migrate gradually instead of rewriting everything at once?
Yes. For many teams, the safest approach is incremental: modernize authentication libraries first, then update app registrations and token validation, then replace Azure AD Graph usage and older permission models in controlled stages.
0

A lot of teams talk about “migrating from Azure AD to Entra ID” as if it were only a branding update.

For some applications, that is mostly true.

But for many real .NET systems, the migration is much more substantial than a rename. The difficult part is usually not the label change from Azure Active Directory to Microsoft Entra ID. The difficult part is modernizing everything around that identity layer:

  • older authentication libraries,
  • Azure AD Graph dependencies,
  • token acquisition patterns,
  • app registration assumptions,
  • multi-tenant behavior,
  • and production hardening choices that were acceptable years ago but now create risk or friction.

That is why this migration deserves to be treated as a real engineering project.

If you do it well, you end up with:

  • cleaner authentication flows,
  • better-supported libraries,
  • stronger token handling,
  • clearer permission models,
  • and a platform that is easier to maintain going forward.

If you do it poorly, you may get login working while quietly breaking:

  • downstream API calls,
  • app-only permissions,
  • role and scope enforcement,
  • or tenant restrictions that mattered more than the old implementation made obvious.

This guide explains how .NET teams should approach Azure AD versus Entra ID in 2026, what the transition really means, how to migrate incrementally, and how to update both code and operational patterns safely.

Executive Summary

The most important thing to understand is this:

For most .NET applications, the important migration is not “identity provider A to identity provider B.” It is “older Azure AD-era implementation patterns to current Microsoft identity platform patterns.”

In practice, that usually means moving from:

  • ADAL-era or older Azure AD authentication libraries,
  • Azure AD Graph usage,
  • outdated startup configuration,
  • overly broad permissions,
  • and weak token handling patterns

to:

  • Microsoft Entra ID terminology and platform alignment,
  • MSAL,
  • Microsoft Identity Web,
  • Microsoft Graph,
  • modern OpenID Connect and OAuth 2.0 flows,
  • and cleaner scope or app-role-based authorization.

A safe migration usually happens in stages:

  1. audit the current implementation
  2. update packages and authentication plumbing
  3. modernize app registrations and permission design
  4. replace Azure AD Graph usage with Microsoft Graph
  5. test token behavior, authorization, and tenant rules carefully
  6. harden the result for production

The main lesson is simple: this is not just a login migration. It is an identity architecture refresh.

Who This Is For

This guide is for:

  • ASP.NET Core developers,
  • backend engineers protecting APIs,
  • teams maintaining older Microsoft identity integrations,
  • and architects planning identity modernization across .NET applications.

It is especially relevant if your system still uses:

  • older Azure AD SDKs,
  • Azure AD Graph,
  • custom token plumbing that predates Microsoft Identity Web,
  • or authentication code that “works” but has become hard to maintain.

Azure AD vs Entra ID: What Actually Changed?

The first thing to get clear is what changed conceptually.

What Stayed the Same

For many enterprise apps, the underlying Microsoft identity platform capabilities remain familiar:

  • OpenID Connect for authentication
  • OAuth 2.0 for authorization
  • JWT access tokens
  • tenant-based identity
  • app registrations
  • delegated and application permissions

If your app was already using modern identity platform patterns, the rename by itself may not require dramatic code changes.

What Changed in Practice

What changed for many teams is the surrounding ecosystem and the recommended implementation model.

The modernization path usually includes:

  • new naming and platform alignment
  • older Azure AD Graph patterns being replaced by Microsoft Graph
  • ADAL-era client logic being replaced by MSAL
  • more consistent use of Microsoft Identity Web in ASP.NET Core
  • clearer separation between workforce identity and customer identity scenarios
  • stronger expectations around secure token validation and permission design

That is why this guide treats the migration as more than a branding exercise.

When You Actually Need a Migration Project

Some teams only need light documentation and naming updates. Others need a real code and platform migration.

Light Migration Scenarios

You may only need a lighter update if:

  • you already use MSAL or Microsoft Identity Web,
  • you already target Microsoft Graph,
  • your app registrations are clean,
  • and the app is already aligned to modern OpenID Connect and OAuth 2.0 flows.

In that case, your work is more about:

  • configuration review,
  • naming cleanup,
  • and validating production hardening.

Full Migration Scenarios

You likely need a real migration project if:

  • you still use Azure AD Graph
  • you still use older Azure AD-era client libraries
  • your startup configuration is based on outdated middleware
  • your API permission model is vague or over-broad
  • your token handling is custom and brittle
  • or multi-tenant behavior is not clearly understood

That is where the migration becomes valuable rather than optional.

Step 1: Audit the Current Identity Surface

Before changing packages or code, audit what you actually have.

A lot of teams start migrating too quickly and only later discover:

  • hidden API dependencies,
  • app-only flows nobody documented,
  • Graph permissions they forgot about,
  • or multiple apps sharing the same registration in unsafe ways.

What to Inventory

Review:

  • app registrations
  • redirect URIs
  • client secrets or certificates
  • API permissions
  • exposed scopes
  • app roles
  • multi-tenant settings
  • Graph usage
  • libraries and NuGet packages
  • token validation behavior
  • any custom auth middleware

Example Audit Model

public class IdentityIntegrationInventory
{
    public string TenantId { get; set; }
    public string ClientId { get; set; }
    public string ClientSecretLocation { get; set; }
    public string Authority { get; set; }
    public string GraphEndpoint { get; set; }
    public string[] DelegatedScopes { get; set; }
    public string[] AppPermissions { get; set; }
    public bool IsMultiTenant { get; set; }
    public bool UsesAzureAdGraph { get; set; }
    public bool UsesCustomJwtValidation { get; set; }
}

Why This Matters

If you do not understand the current identity surface, the migration plan will miss important behavior.

That usually leads to one of two failures:

  • migration looks successful but breaks secondary flows later
  • migration becomes much slower because hidden dependencies keep surfacing mid-project

Step 2: Update Dependencies and Identity Libraries

One of the clearest technical signs that a migration is needed is an older package set.

The goal is not only to upgrade versions. It is to move toward the libraries that fit the current Microsoft identity model better.

Package Direction

The typical modernization path is:

  • remove older Azure AD-era authentication dependencies
  • move to Microsoft Identity Web for ASP.NET Core integration
  • use MSAL for token acquisition patterns
  • use Microsoft Graph SDK for Graph operations

Example Package Direction

<!-- Older packages to remove from legacy setups -->
<!-- <PackageReference Include="Microsoft.Azure.ActiveDirectory.GraphClient" Version="2.x.x" /> -->
<!-- <PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="5.x.x" /> -->

<!-- Modern direction -->
<PackageReference Include="Microsoft.Identity.Web" Version="*" />
<PackageReference Include="Microsoft.Graph" Version="*" />

Why This Matters

Older packages do not only create maintenance pain. They often encourage older flow patterns and make new platform guidance harder to adopt cleanly.

Step 3: Clean Up App Registration Design

A lot of Entra migration pain actually comes from messy app registrations.

This is the right time to simplify them.

Review These Areas

API App Registration

Make sure the API registration has:

  • a clear Application ID URI
  • meaningful exposed scopes
  • app roles if needed
  • supported account type aligned to your tenant strategy

Client App Registration

Make sure the client registration has:

  • the right redirect URIs
  • the right permissions
  • no unnecessary grants
  • secret or certificate handling reviewed
  • tenant model clearly defined

Practical Example

For a protected internal API:

  • API app exposes orders.read and orders.write
  • client app requests only what it needs
  • admin behavior is driven by role assignment or a separate authorization layer

That is much cleaner than one giant access_as_user permission for everything.

Step 4: Update Configuration Structure

Many older apps still have configuration designed around older Azure AD assumptions.

You do not need overly complicated config, but you do need a clear split between:

  • app sign-in configuration
  • protected API configuration
  • downstream API configuration

Example Updated Configuration

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "yourdomain.onmicrosoft.com",
    "TenantId": "your-tenant-id",
    "ClientId": "your-client-id",
    "ClientSecret": "your-client-secret",
    "CallbackPath": "/signin-oidc"
  },
  "MicrosoftGraph": {
    "BaseUrl": "https://graph.microsoft.com/v1.0",
    "Scopes": "User.Read"
  },
  "ProtectedApi": {
    "BaseUrl": "https://localhost:5001",
    "Scopes": "api://elysiate-api/orders.read"
  }
}

Why This Helps

This keeps:

  • identity provider config,
  • Graph config,
  • and custom downstream API config

from getting mixed together in ways that become harder to maintain.

Step 5: Modernize ASP.NET Core Authentication Setup

This is where the migration becomes visible in code.

For many web apps, the modern path is to use Microsoft Identity Web rather than keeping older startup patterns alive.

Web App Authentication Example

using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddMicrosoftGraph(builder.Configuration.GetSection("MicrosoftGraph"))
    .AddInMemoryTokenCaches();

builder.Services.AddControllersWithViews();

var app = builder.Build();

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

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

Why This Pattern Is Better

It reduces:

  • custom auth plumbing
  • manual token acquisition work
  • and brittle startup code

It also aligns more naturally with the current Microsoft identity stack for ASP.NET Core.

Step 6: Protect APIs with Modern JWT Validation

If you are protecting a .NET API, the migration should also include a review of JWT validation.

The main risk here is assuming a signed token is automatically acceptable.

It is not.

Protected API Example

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication()
    .AddJwtBearer("AzureAd", options =>
    {
        options.Authority = builder.Configuration["AzureAd:Authority"];
        options.Audience = builder.Configuration["AzureAd:Audience"];
        options.TokenValidationParameters.ValidateIssuer = true;
    });

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("OrdersRead", policy =>
        policy.RequireClaim("scp", "orders.read"));
});

var app = builder.Build();

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

app.MapGet("/api/orders", () => Results.Ok(new[] { "A123", "B456" }))
   .RequireAuthorization("OrdersRead");

app.Run();

What to Validate Properly

Your API should validate:

  • issuer
  • audience
  • expiration
  • signature
  • tenant restrictions if relevant
  • scopes or roles explicitly

A token that parses correctly but targets the wrong audience is still invalid for your API.

Step 7: Replace Azure AD Graph with Microsoft Graph

This is one of the most important migration steps for older apps.

If your system still relies on Azure AD Graph-era patterns, moving to Microsoft Graph is usually essential.

Old Pattern

Older code often looks like:

  • custom HttpClient
  • legacy graph endpoint
  • custom JSON parsing
  • older token acquisition style

New Pattern

A cleaner Microsoft Graph approach looks like this:

public class MicrosoftGraphService
{
    private readonly GraphServiceClient _graphServiceClient;

    public MicrosoftGraphService(GraphServiceClient graphServiceClient)
    {
        _graphServiceClient = graphServiceClient;
    }

    public async Task<List<User>> GetUsersAsync()
    {
        var users = await _graphServiceClient.Users.GetAsync();
        return users.Value?.ToList() ?? new List<User>();
    }

    public async Task<User?> GetUserAsync(string userId)
    {
        return await _graphServiceClient.Users[userId].GetAsync();
    }
}

Why This Matters

The migration to Microsoft Graph is not only about endpoint preference. It also improves:

  • SDK consistency
  • supported identity patterns
  • permission design clarity
  • and future maintainability

Step 8: Update Token Acquisition Logic

Many older internal services or backends still use older confidential-client patterns that need modernization.

A cleaner app-only token acquisition pattern uses MSAL.

Example

using Microsoft.Identity.Client;

public class EntraIdService
{
    private readonly IConfidentialClientApplication _app;

    public EntraIdService(IConfiguration configuration)
    {
        _app = ConfidentialClientApplicationBuilder
            .Create(configuration["AzureAd:ClientId"])
            .WithClientSecret(configuration["AzureAd:ClientSecret"])
            .WithAuthority($"https://login.microsoftonline.com/{configuration["AzureAd:TenantId"]}")
            .Build();
    }

    public async Task<string> GetAccessTokenAsync()
    {
        var scopes = new[] { "https://graph.microsoft.com/.default" };
        var result = await _app.AcquireTokenForClient(scopes).ExecuteAsync();
        return result.AccessToken;
    }
}

Why This Is Better

It reflects the current app-only acquisition model more clearly and fits modern MSAL patterns better than older ADAL-style code.

Roles, Scopes, and Permission Design

A migration is the perfect time to fix messy authorization design.

One of the most common problems in older identity integrations is overly broad permission design.

Use Scopes For

Scopes are best for:

  • delegated user-to-API access
  • user-context API calls
  • web app and SPA permissions

Examples:

  • orders.read
  • orders.write
  • reports.export

Use App Roles For

App roles are best for:

  • app-only permissions
  • role-based access
  • service-to-service authorization
  • administrative behavior

Practical Rule

Scopes answer: What can this app do on behalf of this user?

Roles answer: What level of access does this principal have in the system?

A lot of cleaner migration outcomes come from finally separating those two concerns properly.

Multi-Tenant and External Identity Scenarios

Migration is also the right time to review whether your tenant model still makes sense.

Multi-Tenant Apps

If the app is multi-tenant:

  • review issuer validation carefully
  • validate tid where needed
  • maintain an allowlist or onboarding model for approved tenants
  • do not trust every organizational tenant automatically unless the product truly intends to

Example Pattern

services.Configure<OpenIdConnectOptions>(
    OpenIdConnectDefaults.AuthenticationScheme,
    options =>
    {
        options.TokenValidationParameters.ValidateIssuer = false;
        options.TokenValidationParameters.IssuerValidator = (issuer, token, parameters) => issuer;
    });

This kind of flexibility can be necessary, but it also increases responsibility. If you allow multiple issuers, you need another way to enforce tenant trust boundaries.

Customer Identity

If your migration effort includes consumer-facing identity scenarios, review whether the workload belongs in a customer identity model rather than being stretched awkwardly into a workforce-style setup.

That often helps keep the architecture more coherent.

Testing the Migration

Identity migrations should be tested more deeply than a normal configuration change.

Too many teams test only:

  • “Can I sign in?”

That is not enough.

Test These Scenarios

Authentication

  • valid sign-in
  • invalid token
  • expired token
  • wrong audience
  • wrong tenant
  • missing claims

Authorization

  • valid scope
  • missing scope
  • valid role
  • missing role
  • cross-tenant denial
  • app-only versus delegated behavior

Downstream Access

  • token acquisition for Graph
  • token acquisition for custom APIs
  • cache behavior
  • secret rotation behavior
  • failure paths when Graph or auth endpoints are unavailable

Token Claim Review

This is also the right time to re-check token claim assumptions.

For example:

public class TokenClaimsService
{
    public UserInfo ExtractUserInfo(ClaimsPrincipal principal)
    {
        return new UserInfo
        {
            ObjectId = principal.FindFirst("oid")?.Value,
            TenantId = principal.FindFirst("tid")?.Value,
            Name = principal.FindFirst("name")?.Value,
            Email = principal.FindFirst("preferred_username")?.Value,
            GivenName = principal.FindFirst("given_name")?.Value,
            FamilyName = principal.FindFirst("family_name")?.Value
        };
    }
}

Do not assume the token claims your older implementation used are still the only ones you care about. Review them intentionally.

Performance and Operational Improvements

A good migration can also improve performance and reliability.

Token Caching

Token acquisition should not be more expensive than it needs to be.

public class CachedTokenService
{
    private readonly IMemoryCache _cache;
    private readonly EntraIdService _entraIdService;

    public async Task<string> GetCachedTokenAsync()
    {
        const string cacheKey = "access_token";

        if (_cache.TryGetValue(cacheKey, out string cachedToken))
        {
            return cachedToken;
        }

        var token = await _entraIdService.GetAccessTokenAsync();

        _cache.Set(cacheKey, token, new MemoryCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(50)
        });

        return token;
    }
}

Why This Helps

Good caching reduces:

  • redundant token requests
  • Graph acquisition overhead
  • and identity service dependency pressure

Monitoring and Logging

Identity migrations should improve visibility, not reduce it.

Track:

  • sign-in failures
  • token acquisition failures
  • downstream Graph failures
  • 401 and 403 rates
  • auth latency
  • tenant-specific anomalies
  • permission-denied patterns

Example Logging Wrapper

public class GraphLoggingService
{
    private readonly ILogger<GraphLoggingService> _logger;

    public async Task<T> LogGraphCallAsync<T>(string operation, Func<Task<T>> graphCall)
    {
        _logger.LogInformation("Starting Graph API call: {Operation}", operation);

        var stopwatch = Stopwatch.StartNew();

        try
        {
            var result = await graphCall();
            stopwatch.Stop();

            _logger.LogInformation(
                "Graph API call completed: {Operation} in {Duration}ms",
                operation, stopwatch.ElapsedMilliseconds);

            return result;
        }
        catch (Exception ex)
        {
            stopwatch.Stop();

            _logger.LogError(
                ex,
                "Graph API call failed: {Operation} in {Duration}ms",
                operation, stopwatch.ElapsedMilliseconds);

            throw;
        }
    }
}

This matters because identity issues often appear first as:

  • downstream call failures
  • auth spikes
  • or permission mismatches

rather than obvious application crashes.

Production Hardening Checklist

A real migration is not complete until the production posture is improved too.

Hardening Priorities

  • Remove older Azure AD-era packages and patterns
  • Use Microsoft Graph instead of Azure AD Graph-era code
  • Narrow scopes and review app roles
  • Validate issuer, audience, expiry, and tenant assumptions
  • Move secrets to secure storage
  • Prefer certificates or stronger secret handling where appropriate
  • Enforce HTTPS and secure cookie settings
  • Add logging and monitoring for auth flows
  • Test multi-tenant and authorization edge cases
  • Document rollback and rollout strategy

Common Migration Mistakes to Avoid

Teams often make the same mistakes:

  • treating the rename as the whole migration
  • updating libraries but not permissions
  • getting login working while leaving authorization too broad
  • migrating Graph code without checking app permissions carefully
  • skipping tenant validation in multi-tenant apps
  • leaving secrets in weak storage locations
  • and not testing app-only flows, delegated flows, and downstream API calls separately

These are the kinds of mistakes that create “successful” migrations that still leave the identity surface weaker than it should be.

A Practical Migration Path

For many teams, the safest migration plan looks like this:

Phase 1: Inventory

  • audit the current auth stack
  • identify package, Graph, and permission dependencies
  • document app registrations and flows

Phase 2: Library Modernization

  • move to Microsoft Identity Web and MSAL where appropriate
  • simplify configuration
  • keep behavior equivalent where possible

Phase 3: Permission and Graph Cleanup

  • replace Azure AD Graph-era code
  • refine scopes and app roles
  • reduce over-broad permissions

Phase 4: Hardening

  • secure secrets
  • improve validation
  • add logging and tests
  • verify tenant boundaries and auth failure behavior

Phase 5: Rollout

  • migrate component by component
  • use feature flags where possible
  • monitor auth, token, and Graph failures carefully
  • keep rollback practical

This is usually safer than trying to rewrite the whole identity layer in one move.

Conclusion

Azure AD versus Entra ID is often presented as a naming conversation, but for many .NET teams the real value is in using the transition as an opportunity to modernize identity properly.

That means:

  • moving off older libraries,
  • cleaning up app registrations,
  • using Microsoft Graph,
  • improving token acquisition,
  • refining scopes and roles,
  • and hardening the whole auth surface for production.

If you approach it that way, the migration becomes more than administrative cleanup.

It becomes a chance to make your .NET authentication architecture:

  • cleaner,
  • more supportable,
  • more secure,
  • and easier to reason about over time.

About the author

Elysiate publishes practical guides and privacy-first tools for data workflows, developer tooling, SEO, and product engineering.

Related posts