9

I do have an Asp.Net MVC Application (version 6.0.0-rc1-final) with custom role and user stores. After some struggling I finally could create a working login mechanism. However I do have now troubles to create a clean logout. What my logout code in the controller currently looks like:

public async Task<ActionResult> Logout()
{
    if (User.Identity.IsAuthenticated)
    {
    await SignInManager.SignOutAsync();

    }

    return RedirectToAction("Index", "App");
}

The problem with this code is, that one cookie is not deleted: .AspNet.Microsoft.AspNet.Identity.Application

As long as I don't delete the cookie manually the application is in a dirty state and throws null pointer exceptions because User.Identity is null.

I have found a question on stackoverflow describing a similar scenario. But the solution there is not appropriate for me because I am using MVC 6 which does not have System.Web any more.

I do also have a sample solution which just works fine. In this solution the mentioned cookie is never created. Perhaps the right solution is not to delete the cookie after logout, but rather to prevent somehow the creation of the cookie.

Community
  • 1
  • 1
marco birchler
  • 1,566
  • 2
  • 21
  • 45

4 Answers4

3

I could fix the dirty state of my application after the logout by manually delete the cookie after the logout action:

public async Task<ActionResult> Logout()
{
    if (User.Identity.IsAuthenticated)
    {
        await SignInManager.SignOutAsync();
    }

    foreach (var key in HttpContext.Request.Cookies.Keys)
    {
        HttpContext.Response.Cookies.Append(key, "", new CookieOptions() { Expires = DateTime.Now.AddDays(-1) });
    }
    return RedirectToAction("Index", "App");
}

As cookies cannot deleted from the server directly I just overwrite the existing cookies with an already passed expiry date.

marco birchler
  • 1,566
  • 2
  • 21
  • 45
  • 1
    I just figured out mine. My problem was I overrided the SignOutAsync incorrectly. After I removed it and use the original one. It works correctly now. – maxisam Apr 25 '16 at 15:29
  • @maxisam Can you elaborate more? I am having the same problem here too. – Haikal Nashuha Aug 06 '17 at 11:05
  • @HaikalNashuha sorry I don't remember what it was now. I believe I was trying to create my own methods for identity server but I overrided SignOutAsync incorrectly. – maxisam Aug 06 '17 at 21:48
3

The problem is that your RedirectToAction overwrites the redirect to the Identity Server endsession URL that SignOutAsync issues.

(The same explanation for the same problem is given here by Microsoft's HaoK.)

Edit: The solution is to send a redirect URL in an AuthenticationProperties object with the final SignOutAsync:

// in some controller/handler, notice the "bare" Task return value
public async Task LogoutAction()
{
    // SomeOtherPage is where we redirect to after signout
    await MyCustomSignOut("/SomeOtherPage");
}

// probably in some utility service
public async Task MyCustomSignOut(string redirectUri)
{
    // inject IHttpContextAccessor to get "context"
    await context.SignOutAsync("Cookies");
    var prop = new AuthenticationProperties()
    {
        RedirectUri = redirectUri
    });
    // after signout this will redirect to your provided target
    await context.SignOutAsync("oidc", prop);
}
McGuireV10
  • 9,572
  • 5
  • 48
  • 64
  • 1
    Unfortunately I can't verify your solution as I am not working any more for this project - but nevertheless your solution sounds very promising to me. – marco birchler Jan 31 '18 at 06:55
  • Yeah I figured you'd moved on, but I see this issue so often I wanted to get the answer out there for a few others because it's a pretty tricky problem. Took me a few days to track it down myself! – McGuireV10 Jan 31 '18 at 10:00
0

In addition to everything already mentioned, also make sure you are not omitting the scheme argument in the calls to SignInAsync and SignOutAsync, and that you are passing the same value to both. For example:

HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);

and

HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

So in this example the scheme is CookieAuthenticationDefaults.AuthenticationScheme. In my case I was forgetting to pass this to SignOutAsync, and while obvious after the fact, it took longer than I'd like to admit for me to track down.

M.J.
  • 51
  • 3
0

Another gotcha that could leave the identity server cookies on the client is a logout failure. One typical cause of logout failures is a misconfiguration of the client’s PostLogoutRedirectUris.

The logout failures are not visible from the client side, the endsession call returns 200 OK, as well as the logout call.

There will however be traces on your identity server logs that the logout failed.

Berthier Lemieux
  • 3,785
  • 1
  • 25
  • 25