Search code examples
c#.netauthenticationasp.net-identityopenid-connect

How do you avoid an infinite redirect loop when combine two different authentication schemes (openIdConnect and ASP.NET Identity)?


I am currently working on a login system where a user has the option to login with either their organization email (AD authentication) or regular email and password as shown below:

Login System

Before adding Identity, I was able to successfully sign in and out with AD authentication. And here's how I achieve that:

Program.cs

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(config.GetRequiredSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(
     ["user.read"]
)
.AddInMemoryTokenCaches();

builder.Services.Configure<OpenIdConnectOptions>(
    OpenIdConnectDefaults.AuthenticationScheme,
    options =>
    {
        options.SignedOutCallbackPath = "/signout-callback-oidc";
        options.SignedOutRedirectUri = "/Identity/Account/SignOut";
    }
);

AccountController.cs

[Route("SignIn")]
[Route("[area]/[controller]/[action]")]
public IActionResult SignIn()
{
    var redirect = Url.Action("Overview", "DashboardView", new { area = "Events" });


    var scheme = OpenIdConnectDefaults.AuthenticationScheme;

    return Challenge(
        new AuthenticationProperties { RedirectUri = redirect },
        scheme
    );
}

[Route("SignOut")]
[Route("[area]/[controller]/[action]")]
public new IActionResult SignOut()
{
    var callbackUrl = Url.Action("LogIn", "Account", new { area = "Identity" }, protocol: Request.Scheme);

    return SignOut(new AuthenticationProperties { RedirectUri = callbackUrl },
        CookieAuthenticationDefaults.AuthenticationScheme,
        OpenIdConnectDefaults.AuthenticationScheme);

}

The problem started to arise when I incorporate Asp.net Identity

Program.cs

builder.Services.AddIdentity<IdentityUser, IdentityRole>()
    .AddEntityFrameworkStores<ActraContext>()
    .AddDefaultTokenProviders();

// Updated AddAuthentication for Identity
builder.Services.AddAuthentication(options => {
        options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddMicrosoftIdentityWebApp(config.GetRequiredSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi(
        ["user.read"]
    )
    .AddInMemoryTokenCaches();

builder.Services.ConfigureApplicationCookie(options => {
    options.LoginPath = "/Identity/Account/SignIn";
    options.LogoutPath = "/Identity/Account/SignOut";
    options.AccessDeniedPath = "";
    options.ReturnUrlParameter = "returnUrl";
});

The code above will create infinite redirect to the action method SignIn and ultimately prevent the user to login with Entra Authentication.

I haven't started on the second part of the authentication (email and password authentication yet.

I read this documentation to incorporate identity and identity entity models Link To Docs

I read this documentation to sign a user in and out with AD authentication Link To Docs


Solution

  • I found the answer by reading this thread

    Here's the updated code

    builder.Services.AddAuthentication(options => {
        options.DefaultScheme = IdentityConstants.ApplicationScheme;
        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
        .AddMicrosoftIdentityWebApp(config.GetRequiredSection("AzureAd"))
        .EnableTokenAcquisitionToCallDownstreamApi(["user.read"])
        .AddInMemoryTokenCaches()
        .AddMicrosoftGraph();
    
    builder.Services.Configure<OpenIdConnectOptions>(
        OpenIdConnectDefaults.AuthenticationScheme,
        options =>
        {
            options.SignInScheme = IdentityConstants.ApplicationScheme;
            options.SignedOutCallbackPath = "/signout-callback-oidc";
            options.SignedOutRedirectUri = "/Identity/Account/SignOut";
        }
    );