title: Logout / Timeout redirect ASP.net Core
body: <p>In my ASP.net core site, after 20 minutes of inactivity, the session expires, and on the next action that the user performs that requires authentication, the site redirects back to /Account/Login. The problem is, I'd like to redirect back to a different page depending on the session that was expired.</p>
  
  <p>For example, people log in to my website at <a href="https://example.com/Account/Login?appId=12345" rel="nofollow noreferrer">https://example.com/Account/Login?appId=12345</a>. However, when the session expires and the user is redirected back to the login page, the appId=12345 is stripped. (12345 could be anything depending on the user). I'm not sure how to include a custom parameter in the redirect URL unique to each session.</p>
  
  <p>Here's how I have the timeout currently configured in Startup.cs:</p>
  
  <pre><code> app.UseCookieAuthentication(new CookieAuthenticationOptions {
        AutomaticAuthenticate = true,
        AutomaticChallenge = true,
        SlidingExpiration = true,
        ExpireTimeSpan = TimeSpan.FromMinutes(20)
        LoginPath = "/Account/Login"
   });
  </code></pre>
  
  <p>I was asked for my httpget and httppost login methods, so here is a very stripped down version (especially the POST method) of them:</p>
  
  <pre><code> [RequireHttps]
   [HttpGet]
   public IActionResult Login(string returnUrl = "/", // The path to direct to after the login is complete
                                 bool activated = false, // If the screen should prompt that the account has been activated. This flag is used from email activation only
                                 string email = null,    // To pre-populate an e-mail address in the username field
                                 bool interactive = false,    // Interactive login (ask for username first, then password OR create user)
                                 string applicationId = null, // An application id (for tblApplications) to format the screen and log directly in to an application
                                 string errorMessage = null
                                ) {
  
          LoginViewModel model = new LoginViewModel();
  
          // Pre-set Username
          model.EmailAddress = email;
  
          // Application
          Guid applicationGuid;
          if (applicationId != null &amp;&amp; Guid.TryParse(applicationId, out applicationGuid)) {
              tblApplication application = dbo.GetSingle&lt;tblApplication&gt;(x =&gt; x.ApplicationGuid == applicationGuid);
              if (application != null) {
                  model.applicationId = applicationId;
                  model.ApplicationTitle = application.Title;
  
                  List&lt;tblSettings&gt; settings = dbo.GetList&lt;tblSettings&gt;(x =&gt; x.ApplicationId == application.ApplicationId).ToList();
                  if (settings.Where(x =&gt; x.SettingMasterId == 41 &amp;&amp; x.SettingValue1 == "1").Count() &gt; 0) model.showHeader = false;
                  if (settings.Where(x =&gt; x.SettingMasterId == 42 &amp;&amp; x.SettingValue1 == "1").Count() &gt; 0) model.showFooter = false;
                  if (settings.Any(x =&gt; x.SettingMasterId == 52)) model.LoginHeader = settings.FirstOrDefault(x =&gt; x.SettingMasterId == 52).SettingValue1;
                  if (settings.Any(x =&gt; x.SettingMasterId == 63 &amp;&amp; x.SettingValue1 != null)) model.themeId = int.Parse(settings.Where(x =&gt; x.SettingMasterId == 63 &amp;&amp; x.SettingValue1 != null).FirstOrDefault().SettingValue1);
                  if (settings.Where(x =&gt; x.SettingMasterId == 67 &amp;&amp; x.SettingValue1 == "1").Count() &gt; 0) model.Interactive = true;
              }
          }
  
          // Return URL after login successful
          ViewData["ReturnUrl"] = returnUrl;
  
          // Activation message from security provider 
          if (activated) model.activated = true;
  
          // Interactive
          if (interactive) model.Interactive = true;
  
          // Error Message
          if (errorMessage != null) model.BannerErrorMessage = errorMessage;
  
          // Return to form
          return View(model);
      }
  
  [HttpPost]
  public async Task&lt;IActionResult&gt; Login(LoginViewModel vm, string returnUrl = null) {
          if (ModelState.IsValid) {
              tblIdentity identity = null;
              try {
  
                  // Pull the client identity record from the database
                  identity = dbo.ExecuteQuery&lt;tblIdentity&gt;(x =&gt; x.ClientId == vm.EmailAddress).FirstOrDefault();
                  if (identity == null)
                      throw new Exception("Invalid Email or Password");
  
                  // ** Authentication Code here. On failure, throw exception
  
                  if (user.EmailVerified == null || user.EmailVerified == false) {
                      // ** Code for email address not verified
                      return RedirectToAction("AccountNotVerified", model);
                  }
                  else {
                      // Call the login procedure to create cookes
                      ClaimsPrincipal claimsPrincipal = await login(identity, user.UserId, user.FullName, user.Email, vm.applicationId);
  
                      // Sign user into cookie middleware
                      await HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal);
  
                      // Redirect back to the return url
                      return RedirectToLocal(returnUrl);
                  }
              }
              catch (Exception e) {
  
                  ModelState.AddModelError("", e.Message);
              }
          }
          return View(vm);
      }
  
      public async Task&lt;ClaimsPrincipal&gt; login(tblClientIdentity identity, string userId, string fullName, string email, string applicationId = null) {
  
          var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[] {
                                                                              new Claim(ClaimTypes.NameIdentifier, userId),
                                                                              new Claim(ClaimTypes.Name, fullName),
                                                                              new Claim(ClaimTypes.Email, email)},
                                                  CookieAuthenticationDefaults.AuthenticationScheme));
  
          // Application
          if (string.IsNullOrWhiteSpace(applicationId) == false) {
              Guid applicationGuid;
              if (Guid.TryParse(applicationId, out applicationGuid)) {
                  tblApplication application = dbo.GetSingle&lt;tblApplication&gt;(x =&gt; x.ApplicationGuid == applicationGuid);
                  if (application != null) {
                      claimsPrincipal.Identities.First().AddClaim(new Claim("ApplicationId", applicationId, ClaimValueTypes.String, "https://example.com"));
                      HttpContext.Session.SetString("ApplicationId", applicationId);
                  }
                  else {
                      if (HttpContext != null) HttpContext.Session.Remove("ApplicationId");
                      RedirectToAction("Login", "Account", new { ErrorMessage = "The application could not be loaded" });
                  }
              }
              else {
                  if (HttpContext != null) HttpContext.Session.Remove("ApplicationId");
              }
          }
          else {
              if (HttpContext != null) HttpContext.Session.Remove("ApplicationId");
          }
          return claimsPrincipal;
      }
  </code></pre>