aspnetcore/migration/fx-to-core/areas/authentication.md
Authentication is a critical component of web applications, handling user identity verification across HTTP requests. When migrating from ASP.NET Framework to ASP.NET Core, authentication presents unique challenges because the two frameworks handle authentication very differently.
For general information about authentication in ASP.NET Core, see xref:security/authentication/index. For information about authorization, see xref:security/authorization/introduction.
ASP.NET Framework and ASP.NET Core have fundamentally different approaches to authentication:
These differences mean you can't simply move your authentication code from Framework to Core without changes.
Different authentication types present varying levels of migration complexity:
Microsoft.Owin cookie authentication middlewareCookieAuthentication middleware with different configurationMicrosoft.AspNetCore.Authentication.JwtBearerSystem.Web.Security.FormsAuthenticationIHttpModuleYou have three main approaches for handling authentication during migration:
For most applications, migrating to native ASP.NET Core authentication provides the best performance and maintainability. However, larger applications or those with complex authentication requirements may benefit from an incremental approach using the System.Web adapters.
You have three main options for migrating authentication from ASP.NET Framework to ASP.NET Core. Your choice depends on your authentication type, migration timeline, whether you need to run both applications simultaneously, and how much code you're willing to rewrite.
Answer these questions to choose your approach:
Are you doing a complete rewrite or incremental migration?
What type of authentication does your ASP.NET Framework app use?
Do both your ASP.NET Framework and ASP.NET Core apps need to access the same authentication state?
Can you configure matching data protection settings between both apps?
| Approach | Code Changes | Performance | Auth Sharing | When to Use |
|---|---|---|---|---|
| Complete rewrite | High - Rewrite all auth code | Best | None | Complete rewrites, performance-critical apps, non-OWIN auth |
| Remote authentication | Low - Keep existing patterns | Fair | Full | Incremental migrations, complex auth, Windows auth |
| Shared cookies | Medium - Update configuration | Good | Full | OWIN cookie auth, performance-critical shared auth (see Alternatives) |
Choose this approach when you're performing a complete migration, have non-OWIN authentication, or want the best performance and maintainability.
ASP.NET Core provides comprehensive authentication support with high performance and extensive customization options. This approach requires rewriting authentication code but offers the most benefits in the long term.
| Pros | Cons |
|---|---|
| Best performance and security | Requires rewriting all authentication code |
| Native ASP.NET Core implementation | No automatic migration path |
| Full control over authentication flow | Learning curve for new authentication patterns |
| No additional dependencies | Breaking change from Framework patterns |
| Access to latest ASP.NET Core auth features | Potential downtime during migration |
When migrating to native ASP.NET Core authentication:
Choose based on your Framework authentication type:
Code changes required:
HttpContext.User access patterns (mostly compatible)Program.csWhen to choose this approach:
Choose this approach when you need to share authentication between your ASP.NET Framework and ASP.NET Core applications during incremental migration, or when you have complex authentication that's difficult to migrate.
The System.Web adapters' remote authentication feature allows an ASP.NET Core app to determine a user's identity by deferring to an ASP.NET app. This enables gradual migration while maintaining a single authentication system.
RemoteAuthenticationAuthHandler will attempt to authenticate the user.Authorization and Cookie headers).ClaimsPrincipal or an HTTP status code indicating failure.| Pros | Cons |
|---|---|
| Minimal code changes required | Additional HTTP request overhead |
| Works with any Framework auth type | Network dependency between apps |
| Gradual migration capability | More complex debugging |
| Preserves existing auth logic | Requires both apps to be running |
| Handles complex auth scenarios | Limited Windows auth support |
Choose Remote Authentication when:
Microsoft.Owin cookie authenticationThere are just a few small code changes needed to enable remote authentication in a solution that's already set up according to the Getting Started.
First, follow the remote app setup instructions to connect the ASP.NET Core and ASP.NET apps. Then, there are just a couple extra extension methods to call to enable remote app authentication.
:::zone pivot="manual"
The ASP.NET app needs to be configured to add the authentication endpoint. Adding the authentication endpoint is done by calling the AddAuthenticationServer extension method to set up the HTTP module that watches for requests to the authentication endpoint. Note that remote authentication scenarios typically want to add proxy support as well, so that any authentication related redirects correctly route to the ASP.NET Core app rather than the ASP.NET one.
:::code language="csharp" source="~/migration/fx-to-core/areas/authentication/samples/AspNetApp.cs" id="snippet_SystemWebAdapterConfiguration" :::
Next, the ASP.NET Core app needs to be configured to enable the authentication handler that will authenticate users by making an HTTP request to the ASP.NET app. Again, this is done by calling AddAuthenticationClient when registering System.Web adapters services:
:::code language="csharp" source="~/migration/fx-to-core/areas/authentication/samples/AspNetCore.cs" id="snippet_AddSystemWebAdapters" highlight="8" :::
The boolean that is passed to the AddAuthenticationClient call specifies whether remote app authentication should be the default authentication scheme. Passing true will cause the user to be authenticated via remote app authentication for all requests, whereas passing false means that the user will only be authenticated with remote app authentication if the remote app scheme is specifically requested (with [Authorize(AuthenticationSchemes = RemoteAppAuthenticationDefaults.AuthenticationScheme)] on a controller or action method, for example). Passing false for this parameter has the advantage of only making HTTP requests to the original ASP.NET app for authentication for endpoints that require remote app authentication but has the disadvantage of requiring annotating all such endpoints to indicate that they will use remote app auth.
:::zone-end
:::zone pivot="aspire" When using Aspire, the configuration will be done via environment variables and are set by the AppHost. To enable remote session, the option must be enabled:
...
var coreApp = builder.AddProject<Projects.AuthRemoteIdentityCore>("core")
.WithHttpHealthCheck()
.WaitFor(frameworkApp)
.WithIncrementalMigrationFallback(frameworkApp, options => options.RemoteAuthentication = RemoteAuthentication.DefaultScheme);
...
Once this is done, it will be automatically hooked up in both the framework and core applications. :::zone-end
When using remote authentication with YARP-based fallback to the ASP.NET Framework app, make sure that fallback requests don't invoke remote authentication. If remote authentication runs during fallback, the app makes unnecessary extra calls back to the Framework app and can lead to confusing behavior.
To avoid running remote authentication for fallback requests, use one of these approaches:
ShortCircuit on the fallback endpoint as shown in the remote app setup guidance and in Short-circuit middleware after routing.false to AddAuthenticationClient and specify the remote authentication scheme explicitly on those endpoints.When you set the default scheme to false, you can specify remote authentication for specific controllers or actions:
[Authorize(AuthenticationSchemes = RemoteAppAuthenticationDefaults.AuthenticationScheme)]
public class SecureController : Controller
{
// This controller uses remote authentication
public IActionResult Index()
{
return View();
}
}
// Or on specific actions
public class HomeController : Controller
{
[Authorize(AuthenticationSchemes = RemoteAppAuthenticationDefaults.AuthenticationScheme)]
public IActionResult SecureAction()
{
return View();
}
}
You can implement custom processors to modify authentication results before they are used:
public class CustomAuthResultProcessor : IRemoteAuthenticationResultProcessor
{
public Task ProcessAsync(RemoteAuthenticationResult result, HttpContext context)
{
// Custom logic to process authentication results
if (result.Headers.ContainsKey("Location"))
{
// Modify redirect URLs or other logic
}
return Task.CompletedTask;
}
}
// Register the custom processor
builder.Services.AddScoped<IRemoteAuthenticationResultProcessor, CustomAuthResultProcessor>();
Finally, if the ASP.NET Core app didn't previously include authentication middleware, that will need to be enabled (after routing middleware, but before authorization middleware). For more information about middleware ordering, see xref:fundamentals/middleware/index#middleware-order:
:::code language="csharp" source="~/migration/fx-to-core/areas/authentication/samples/AspNetCore.cs" id="snippet_UseAuthentication" :::
When implementing remote authentication, consider the following security aspects:
Common issues when configuring remote authentication:
RedirectUrlProcessor is properly configured to redirect to the ASP.NET Core app rather than the ASP.NET app.ClaimsPrincipal and that all required claims are included.RemoteAuthenticationAuthHandler will attempt to authenticate the user.
Authorization and Cookie headers. The API key header is also added for security purposes.RemoteAuthenticationAuthHandler receives the response from the ASP.NET app:
IRemoteAuthenticationResultProcessor implementations with the ASP.NET Core app which will run on any authentication results before they are used. As an example, the one built-in IRemoteAuthenticationResultProcessor is RedirectUrlProcessor which looks for Location response headers returned from the authenticate endpoint and ensures that they redirect back to the host of the ASP.NET Core app and not the ASP.NET app directly.This remote authentication approach has a couple known limitations:
If authentication in the ASP.NET app is done using Microsoft.Owin Cookie Authentication Middleware, an alternative solution to remote authentication is to configure the ASP.NET and ASP.NET Core apps so that they are able to share an authentication cookie.
Sharing an authentication cookie enables:
Both applications are configured to:
This allows users authenticated in one app to be automatically authenticated in the other app when they make requests.
| Pros | Cons |
|---|---|
| Best performance for shared auth | Only works with OWIN cookie auth |
| No additional HTTP requests | Requires matching data protection setup |
| Both apps can handle sign-in/sign-out | More complex initial configuration |
| Seamless user experience | Limited to cookie-based authentication |
| Lower network overhead | Requires coordination of deployments |
Note that because signing in typically depends on a specific database, not all authentication functionality will work in both apps:
Details on how to configure sharing auth cookies between ASP.NET and ASP.NET Core apps are available in cookie sharing documentation. For more information about cookie authentication in ASP.NET Core, see xref:security/authentication/cookie. For guidance on configuring <machineKey> and data protection when sharing protected values between Framework and Core apps, see xref:migration/fx-to-core/areas/machine-key.
The following samples in the System.Web adapters GitHub repo demonstrates remote app authentication with shared cookie configuration enabling both apps to sign users in and out:
Choose Shared Cookie Authentication when:
Microsoft.Owin cookie authenticationSharing authentication is a good option if both the following are true:
Microsoft.Owin cookie authentication.For other scenarios, the remote authentication approach described previously in this doc is more flexible and is probably a better fit.