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.