Asp.net-mvc – IdentityServer4 signin-oidc page is redirecting to login page infinitely

asp.net-coreasp.net-mvcidentityserver4

I am trying to implement a custom Login button on my MVC app that will direct to the IdentityServer for login and then redirect back to my MVC app.

To do this, I'm using the Microsoft.AspNetCore.Authentication.ChallengeAsync extension method on HttpContext in my Account/Login action

public Task Login()
{
    return HttpContext.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme);
}

The request is directed to the authorize endpoint on the IDP, the user can login and the request is redirected to signin-oidc on my MVC app. It's at this point that signin-oidc calls the Account/Login action and starts looping infinitely.

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET https://localhost:4500/Account/Login
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
      Executing action methodLanding.Controllers.AccountController.Login (Landing) with arguments ((null)) - ModelState is Valid
info: Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler[12]
      AuthenticationScheme: OpenIdConnect was challenged.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action Landing.Controllers.AccountController.Login (Landing) in 11.9704ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 23.4211ms 302
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 POST https://localhost:4500/signin-oidc application/x-www-form-urlencoded 1488
info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[10]
      AuthenticationScheme: Cookies signed in.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 10.4219ms 302
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET https://localhost:4500/Account/Login
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
      Executing action methodLanding.Controllers.AccountController.Login (Landing) with arguments ((null)) - ModelState is Valid

I assume signin-oidc cannot save the cookie and is assuming the login was unsuccessful. The relevant config for the MVC app looks like this

services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;

    options.Authority = Constants.Authority;
    options.RequireHttpsMetadata = true;

    options.ClientId = "mvc";

    options.SaveTokens = true;
});

On the IDP, the client is registered as so

new Client
{
    ClientId = "mvc",
    ClientName = "MVC Client",
    AllowedGrantTypes = GrantTypes.Implicit,
    RequireConsent = false,

    RedirectUris = { "https://localhost:4500/signin-oidc" },
    PostLogoutRedirectUris = { "https://localhost:4500/signout-callback-oidc" },

    AllowedScopes =
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
    },
}

How can I get this flow with ChallengeAsync to work correctly?

Best Answer

To anyone looking at this in the future: There is an overload of ChallengeAsync that allows you to pass in a redirectUrl that you want signin-oidc to send the user to after successful login. Once this is set, the infinite redirect doesn't occur.

return HttpContext.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties
{
    RedirectUri = "/",
});
Related Topic