(I posted this same message on the Auth0 Forum, but I'm asking here too in case it is not an authentication issue.)
I have a .NET Core application that uses Auth0's Authentication API to authenticate Active Directory users. All of that works as expected. When I run the app from Visual Studio 2015 and open it in my browser, it seems to remember my previous login and does not redirect me to sign in again for a while (the valid length of the JWT, perhaps?).
When the app is published to IIS on Windows Server 2012, users are signed out after about 20 minutes of inactivity.
My research so far has led me to articles about changing the settings of the App Pool in IIS to allow longer sessions. I can't help but think that maybe there is a better way, by re-checking the cookie or something. I would be happy to post the code from my Startup.cs
file or whatever else might be helpful.
Is it possible to re-authenticate users automatically using the OIDC/cookie middleware rather than extending the IIS session time? If the best practice is to extend the session, feel free to tell me that too.
Any tips to point me in the right direction would be greatly appreciated. Thanks!
Update (Code Snippets)
Here's some code to look at! I need another pair of eyes on it.
Here is my ConfigureServices
method in Startup.cs
:
public void ConfigureServices(IServiceCollection services)
{
services.AddRouting(options => options.LowercaseUrls = true);
// Add authentication services
services.AddAuthentication(
options => options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme);
services.AddScoped<IMyRepository, MyRepository>();
// Add framework services.
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
if (_env.IsProduction())
{
config.Filters.Add(new RequireHttpsAttribute());
}
});
// Add functionality to inject IOptions<T>
services.AddOptions();
// Add the Auth0 Settings object so it can be injected
services.Configure<Auth0Settings>(Configuration.GetSection("Auth0"));
}
And here is my Configure
method:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IOptions<Auth0Settings> auth0Settings)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
// Add the cookie middleware
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true
});
// Add the OIDC middleware
var options = new OpenIdConnectOptions("Auth0")
{
// Set the authority to our Auth0 domain
Authority = $"https://{auth0Settings.Value.Domain}",
// Configure the Auth0 Client ID and Client Secret
ClientId = auth0Settings.Value.ClientId,
ClientSecret = auth0Settings.Value.ClientSecret,
// Do not automatically authenticate and challenge
AutomaticAuthenticate = false,
AutomaticChallenge = false,
// Set response type to code
ResponseType = "code",
// Set the callback path, so Auth0 will call back to http://localhost:5000/signin-auth0
// Also ensure that you have added the URL as an Allowed Callback URL in your Auth0 dashboard
CallbackPath = new PathString("/signin-auth0"),
// Configure the Claims issuer to be Auth0
ClaimsIssuer = "Auth0",
Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = context =>
{
if (context.Properties.Items.ContainsKey("connection"))
context.ProtocolMessage.SetParameter("connection", context.Properties.Items["connection"]);
return Task.FromResult(0);
}
}
};
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("name");
options.Scope.Add("email");
options.Scope.Add("groups");
options.Scope.Add("roles");
app.UseOpenIdConnectAuthentication(options);
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Customer}/{action=Index}/{id?}");
});
}
For good measure, this is my Login
method in my account controller:
[AllowAnonymous]
[HttpPost]
public async Task<IActionResult> Login(LoginViewModel vm, string returnUrl = null)
{
if (ModelState.IsValid)
{
try
{
AuthenticationApiClient client = new AuthenticationApiClient(new Uri($"https://{_auth0Settings.Domain}"));
var result = await client.AuthenticateAsync(new AuthenticationRequest
{
ClientId = _auth0Settings.ClientId,
Scope = "openid name email groups",
Connection = "<trimmed>",
Username = vm.Username,
Password = vm.Password
});
// Get user info from token
var user = await client.GetTokenInfoAsync(result.IdToken);
// Create claims principal
var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.NameIdentifier, user.UserId),
new Claim(ClaimTypes.Name, user.FullName),
new Claim(ClaimTypes.Email, user.Email)
}, CookieAuthenticationDefaults.AuthenticationScheme));
// Sign user in to cookie middleware **LOOK**
await HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal);
return RedirectToLocal(returnUrl);
}
catch (ApiException ex)
{
// trimmed...
}
catch (Exception ex)
{
// trimmed...
}
}
return View(vm);
}