This is similar to IdentityServer4 Force User to re-enter credentials, but the solution there says to use prompt=login
query string in the /authorize
URL, which works, but also allows for sneaky users to remove it. Also, seeing as I'm not using .AddOpenIdConnect()
the suggestion to use OnRedirectToIdentityProvider
doesn't apply to me.
So how can we force the user to always enter credentials without relying on the prompt=login
in the query string?
Here's my basic IdentityServer4 setup:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
var builder = services.AddIdentityServer()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApis())
.AddInMemoryClients(Config.GetClients());
builder.AddDeveloperSigningCredential();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseHttpsRedirection();
app.UseFileServer();
app.UseIdentityServer();
app.UseMvc();
}
Where my login page only has an "OK" and "Cancel" button (I don't care which user logs on yet, only that authentication was OK or not), and the controller does the following when it is authenticating the user:
public async Task<IActionResult> Post(AuthenticateViewModel model, string button)
{
var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);
if (button == "authCancel")
{
if (context != null)
{
await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);
return Redirect(model.ReturnUrl);
}
return Redirect("~/");
}
if (button == "authOk" && ModelState.IsValid)
{
if (context != null)
{
await _events.RaiseAsync(new UserLoginSuccessEvent("provider", "userId", "subjectId", "name"));
await HttpContext.SignInAsync("subject", "name", new AuthenticationProperties());
return Redirect(model.ReturnUrl);
}
}
return Redirect("~/");
}
You should be able to achieve desired behaviour by overriding the default cookie scheme that
AddIdentityServer()
registers internally:Make sure you add the override scheme after
AddIdentityServer()
, the sequence here is important due to the way ASP.Net Core DI works.An option could be to stick to
prompt=login
for all requests or based on some client setting, or a http header.It is easy to look into the default request validator and implement your customization like the following:
and then in your Identityserver startup: