I am attempting to force Identity Server 4 (v 2.1.1) with ASP.Net Identity to redirect to the Login page after a certain period. I have set every token lifetime/timeout I can to 1 minute and even accounting for a 5 minute skew Identity Server keeps re-authenticating the user automatically (i.e. no login page required).
Here is the pertinent code
IdentityServer Startup.cs:
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddIdentityServer(options =>
{
options.Authentication.CookieLifetime = TimeSpan.FromSeconds(60);
options.Authentication.CookieSlidingExpiration = false;
})
.AddSigningCredential(certificate)
.AddInMemoryClients(Clients.GetClients())
.AddInMemoryApiResources(Resources.GetApiResources())
.AddInMemoryIdentityResources(Resources.GetIdentityResources())
.AddAspNetIdentity<ApplicationUser>()
.AddJwtBearerClientAuthentication();
Config.GetGlients():
// WebForms Client
new Client
{
...
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
AllowAccessTokensViaBrowser = true,
AuthorizationCodeLifetime = 60,
AccessTokenLifetime = 60,
IdentityTokenLifetime = 60,
RefreshTokenExpiration = TokenExpiration.Absolute,
AbsoluteRefreshTokenLifetime = 60,
SlidingRefreshTokenLifetime = 60
},
Web-Forms Client Middleware Layer:
public void AuthSetup(IAppBuilder app)
{
// Use Cookies to Store JWT Token for Web Browsers
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
ExpireTimeSpan = TimeSpan.FromMinutes(1),
SlidingExpiration = true
});
JwtSecurityTokenHandler.InboundClaimTypeMap.Clear();
// Authenticate to Auth Server
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
AuthenticationType = "oidc",
SignInAsAuthenticationType = "Cookies",
Authority = "http://localhost:5002/",
ClientId = "client",
RedirectUri = "http://localhost:8888/",
PostLogoutRedirectUri = "http://localhost:8888/",
ResponseType = "code id_token token",
Scope = "openid profile AuthApi",
UseTokenLifetime = false,
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = async n =>
{
var claimsToExclude = new[] { "aud", "iss", "nbf", "exp", "nonce", "iat", "at_hash", "c_hash", "idp", "amr" };
var claimsToKeep = n.AuthenticationTicket.Identity.Claims.Where(x => false == claimsToExclude.Contains(x.Type)).ToList();
claimsToKeep.Add(new Claim("id_token", n.ProtocolMessage.IdToken));
if (n.ProtocolMessage.AccessToken != null)
{
// Add access_token so we don't need to request it when calling APIs
claimsToKeep.Add(new Claim("access_token", n.ProtocolMessage.AccessToken));
var userInfoClient = new UserInfoClient(new Uri(n.Options.Authority + "connect/userinfo").ToString());
var userInfoResponse = await userInfoClient.GetAsync(n.ProtocolMessage.AccessToken);
var userInfoClaims = userInfoResponse.Claims
.Where(x => x.Type != "sub") // filter sub since we're already getting it from id_token
.Select(x => new Claim(x.Type, x.Value));
claimsToKeep.AddRange(userInfoClaims);
}
var ci = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType, "name", "role");
ci.AddClaims(claimsToKeep);
n.AuthenticationTicket = new AuthenticationTicket(ci, n.AuthenticationTicket.Properties);
},
RedirectToIdentityProvider = n =>
{
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
n.ProtocolMessage.IdTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token")?.Value;
return Task.FromResult(0);
}
}
});
app.UseStageMarker(PipelineStage.Authenticate);
}
What other setting(s) am I missing to force the server to require the user to login after the token expiration?
Identity Server creates it's own authentication cookie "idsrv" that by default has a lifetime of 10 hours. For 10 hours it will reauthenticate you automatically. To change this default you can change the CookieLifetime
property when configuring Identity Server e.g.
services.AddIdentityServer(options =>
{
options.Authentication.CookieLifetime = TimeSpan.FromSeconds(60);
})
.AddSigningCredential(certificate)
.AddInMemoryClients(Clients.GetClients())
.AddInMemoryApiResources(Resources.GetApiResources())
.AddInMemoryIdentityResources(Resources.GetIdentityResources())
.AddAspNetIdentity<ApplicationUser>()
.AddJwtBearerClientAuthentication();
Also, in your WebForms client OpenIdConnectAuthenticationOptions
you may want to set the UseTokenLifetime
property to true
.