2

I'm unable to log off the user in an MVC 5 app using ASP.NET Identity with Owin (latest versions). Login works great...but I can't log the user off without opening the browser settings to delete the cookie.

When the LogOff action runs, the browser redirects to the designated page which has the [Authorize] attribute. It should be rejected at that point and redirected to the Login page.

Note that if I manually delete the cookies, it will redirect correctly when attempting to open the [Authorize] page, so the redirect action for unauthenticated users is working correctly.

I see a lot of similar questions and have tried the solutions, but nothing is working so far.

I changed:

AuthenticationManager.SignOut();

To:

AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);

as suggested in previous answers, but it didn't change the behavior.

Login works fine. I notice after attempting to LogOff, there are two cookies with the same name instead of just one. One cookie is empty, and one is not.

Here's my LogOff method:

[HttpPost]
    [AllowAnonymous]
    public ActionResult LogOff()
    {
        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);

        //Clear the principal to ensure the user does not retain any authentication
        HttpContext.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);

        // Redirect to a controller/action that requires authentication to ensure a redirect takes place
        // this clears the Request.IsAuthenticated flag since this triggers a new request
        return RedirectToLocal(String.Empty);
    }

And my OwinStartup class:

public class OwinStartup
{
    public void Configuration(IAppBuilder app)
    {
        ConfigureAuth(app);
    }

    // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
    public void ConfigureAuth(IAppBuilder app)
    {
        // UserManagerFactory = () => new UserManager<IdentityUser>(new UserStore<IdentityUser>(new TenantDbContext()));

        // Configure the db context, user manager and signin manager to use a single instance per request
        app.CreatePerOwinContext(TenantDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

        // Enable the application to use a cookie to store information for the signed in user
        // and to use a cookie to temporarily store information about a user logging in with a third party login provider
        // Configure the sign in cookie
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            CookieSecure = CookieSecureOption.Always,
            Provider = new CookieAuthProvider
            {
                // Enables the application to validate the security stamp when the user logs in.
                // This is a security feature which is used when you change a password or add an external login to your account.  
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
            }
        });

        AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
    }

    public class CookieAuthProvider : CookieAuthenticationProvider
    {
        public override void ResponseSignIn(CookieResponseSignInContext context)
        {
            context.CookieOptions.Domain = context.Request.Uri.Host;   
            base.ResponseSignIn(context);
        }
    }
}

And here's my AuthenticationManager:

private IAuthenticationManager AuthenticationManager
    {
        get
        {
            return HttpContext.GetOwinContext().Authentication;
        }
    }
Trevor
  • 69
  • 1
  • 8
  • I don't think it is necessary to call to remove the principal as well. The link below seems to suggest that calling logout more than once can lead to your problem. I don't wkno why. `Request.GetOwinContext().Authentication.SignOut(); Request.GetOwinContext().Authentication.SignOut(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie); HttpContext.Current.GetOwinContext().Authentication.SignOut(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie)` – tacos_tacos_tacos Jun 27 '15 at 02:15
  • If you call them more than once it can create a new login according to this question not that long ago http://stackoverflow.com/questions/28999318/owin-authentication-signout-doesnt-seem-to-remove-the-cookiev ... this guy says "I know my answer isint the most reaserch based, but to tell you the truth, I just couldn't find WHY my provided code examples work for me. I just know that System.Web fucks up Owins cookies if you do SignOut() another way... " – tacos_tacos_tacos Jun 27 '15 at 02:16
  • SignOut is called only once...tried it without removing the principal as well to no avail. – Trevor Jun 27 '15 at 02:34
  • Why did you subclass/override the CookieAuthprovider / also what are the names of the cookies if you can see them in Fiddler? I usally am able to see they come from .NET unless its lockeddown – tacos_tacos_tacos Jun 27 '15 at 02:38
  • The ResponseSignIn method on the CookieAuthProvider was overridden because I'm using multiple sub-domains. I tested it without the overridden method, but it didn't make a difference on the LogOff issue. The cookie names are ".AspNet.ApplicationCookie" (2 with the same name). – Trevor Jun 27 '15 at 02:53
  • One more thing - make sure you are setting your `getUserIdCallback` if applicable in the same function | http://tech.trailmax.info/2014/08/cookieauthenticationprovider-and-user-session-invalidation-on-change-of-securitystamp/ | If cookie validation function can’t get an instance of UserManager, it will not be able to compare the security stamp in cookie with security stamp in the database and the CookieValidator won’t be able to invalidate the cookie. So your code should look like this: – tacos_tacos_tacos Jun 27 '15 at 03:02
  • Also, not sure if this is an issue for you, but since you mentioend multiple domains, if they happened to be on separate kmachines, each machine would have a different key, and so youd have to manually force them to be the same for encryption – tacos_tacos_tacos Jun 27 '15 at 03:06
  • After IISReset, I'm getting only 1 cookie now as it should be. Still can't LogOff though... – Trevor Jun 27 '15 at 03:06
  • 1
    Well, there's also this - http://stackoverflow.com/questions/28252478/how-is-owin-able-to-set-the-asp-net-identity-authentication-cookies-after-the-ap?rq=1 - it seems like the common thread for these is the subdomains. – tacos_tacos_tacos Jun 27 '15 at 03:11
  • Well there you have it...I tested it without a subdomain and it works. This gives me something to work on. Thanks for your help! – Trevor Jun 27 '15 at 03:29
  • No problem at all, I know how much it suck debugging that crap. I didn't quite get why you needed separate domains anyway (unless username is not unique across domains) but that's another story. There's probably some method(s) that assume one domain in a default implementation and thats where you're probably looking – tacos_tacos_tacos Jun 27 '15 at 03:35
  • I solved it by: Request.GetOwinContext().Authentication.SignOut(DefaultAuthenticationTypes.ApplicationCookie); FederatedAuthentication.SessionAuthenticationModule.SignOut(); – SeeSharp Aug 20 '16 at 07:47

0 Answers0