#StackBounty: #asp.net #authentication #session #asp.net-identity #owin Web application logging off user even if isPersistent is set to…

Bounty: 50

I’m using Microsoft.Owin and Microsoft.AspNet.Identity libraries in ASP.NET web application for user authentication. As you can see in the code below, the IsPersistent property is set to true and ExpiresUtc is set to 5 years from now.

So, when user loggs in, the ApplicationCookie is created and user is logged in as long as activity is present. After few hours of inactivity (I don’t yet know the time limit at which logout occurs) the application loggs off user automatically, even if authentication is set to persistent and the Expiry date is 5 years from now. I also tried setting sessionState property in Web.config to 500000, but still no luck.

I want to keep user logged in as long as possible. What am I missing? I have to mention that this only happens in production, while it didn’t yet happen in executing the application locally, using IIS Express on my machine, but that could be for another reason.

Here’s the authentication setup code:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
      AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
      LoginPath = new PathString("/Account/Login"),
      ExpireTimeSpan = TimeSpan.FromDays(1825),
      CookieHttpOnly = true,
      SlidingExpiration = true
});

app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

var facebookOptions = new FacebookAuthenticationOptions()
{
      AppId = "...",
      AppSecret = "...",
      BackchannelHttpHandler = new FacebookBackChannelHandler(),
      UserInformationEndpoint = "https://graph.facebook.com/v2.8/me?fields=id,name,email,first_name,last_name",
      Scope = { "email" }
};

var google = new GoogleOAuth2AuthenticationOptions()
{
      ClientId = "...",
      ClientSecret = "...",
      Provider = new GoogleOAuth2AuthenticationProvider()
};
google.Scope.Add("email");

app.UseGoogleAuthentication(google);
app.UseFacebookAuthentication(facebookOptions);

And here’s the code used for logging in using external login providers:

private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
    AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
    var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
    var rememberBrowserIdentity = AuthenticationManager.CreateTwoFactorRememberBrowserIdentity(user.Id.ToString());

    AuthenticationManager.SignIn(
        new AuthenticationProperties {
            IsPersistent = isPersistent,
            AllowRefresh = true,
            ExpiresUtc = DateTime.UtcNow.AddDays(1825)
        }, 
        identity, 
        rememberBrowserIdentity
    );
}


[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ExternalLogin(string provider, string returnUrl)
{
    Session["Workaround"] = 0;
    return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
}


[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
    var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
    if (loginInfo == null)
    {
        return RedirectToAction("Login");
    }
    ApplicationUser user = null;
    try
    {
        user = await UserManager.FindAsync(loginInfo.Login);
    }catch(Exception exception)...

    if (user != null)
    {
        try
        {
            await SignInAsync(user, isPersistent: true);
        }catch (Exception exception)...

        return RedirectToLocal(returnUrl);
    }
    else
    {
        ViewBag.ReturnUrl = returnUrl;
        ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
        return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { ImePrezime = loginInfo.ExternalIdentity.Name, LoginProvider = loginInfo.Login.LoginProvider, ImePrezimeNaPosluzitelju = loginInfo.ExternalIdentity.Name, Mail = loginInfo.Email, UserName = loginInfo.DefaultUserName });
    }
 }


 [HttpPost]
 [AllowAnonymous]
 [ValidateAntiForgeryToken]
 public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl)
 {
    if (ModelState.IsValid)
    {
        var info = await AuthenticationManager.GetExternalLoginInfoAsync();
        var user = new ApplicationUser(){...};

        try
        {
            var result = await UserManager.CreateAsync(user);

            if (result.Succeeded)
            {
                var roleresult = UserManager.AddToRole(user.Id, "User");
                try
                {
                    result = await UserManager.AddLoginAsync(user.Id, info.Login);
                    if (result.Succeeded)
                    {
                        IKorisniciBL IKorisniciBL = BLFactory.KreirajInstancuKorisnika<IKorisniciBL>();

                        IKorisniciBL.DodajKorisnika(user.Id, user.ImePrezimeNaPosluzitelju, user.ImePrezime, user.UlicaKucniBroj, postanskiBroj, user.Mjesto, user.BrojTelefona, user.Email);
                        await SignInAsync(user, isPersistent: true);
                        return RedirectToLocal(model.ReturnUrl);
                    }
                }
                catch (Exception ex)...
            }
        }
        catch(Exception ex)...
    }

    ViewBag.ReturnUrl = model.ReturnUrl;
    return View(model);
}

And here is the ChallengeResult class where you can also see isPersistent property is set to true and ExpiresUtc to max value.

private class ChallengeResult : HttpUnauthorizedResult
{
    public ChallengeResult(string provider, string redirectUri) : this(provider, redirectUri, null)
    {
    }

    public ChallengeResult(string provider, string redirectUri, string userId)
    {
        LoginProvider = provider;
        RedirectUri = redirectUri;
        UserId = userId;
    }

    public string LoginProvider { get; set; }
    public string RedirectUri { get; set; }
    public string UserId { get; set; }

    public override void ExecuteResult(ControllerContext context)
    {
        var properties = new AuthenticationProperties() { RedirectUri = RedirectUri, IsPersistent = true, ExpiresUtc = DateTime.MaxValue, AllowRefresh = true };
        if (UserId != null)
        {
            properties.Dictionary[XsrfKey] = UserId;
        }
        context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
    }
}


Get this bounty!!!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.