5
votes

I'm writing a Web API with ASP.NET and Identity 2.0 right know. The API should be only accessible, if a user is 'logged in' successfully. The login is working wonderful, but the logout (signout) doesn't seem to work. Here's some code I'm using:

Identity Configuration:

public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }

public void Configuration(IAppBuilder app)
{
    app.CreatePerOwinContext<IdentityDbContext<IdentityUser>>(HLAccountManager.CreateDbContext);
    app.CreatePerOwinContext<UserManager<IdentityUser>>(HLAccountManager.CreateUserManager);

    OAuthBearerOptions = new OAuthBearerAuthenticationOptions();

    app.UseOAuthBearerAuthentication(OAuthBearerOptions);
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/Account/Login")
    });

    GlobalConfiguration.Configuration.SuppressDefaultHostAuthentication();
    GlobalConfiguration.Configuration.Filters.Add(new HostAuthenticationFilter("Bearer"));
}

Authentication Controller:

[HttpPost]
[ActionName("Authenticate")]
[AllowAnonymous]
public String Authenticate(JObject data)
{
    dynamic json = data;
    string user = json.user;
    string password = json.password;

    if (string.IsNullOrEmpty(user) || string.IsNullOrEmpty(password))
        return "failed";

    var userIdentity = UserManager.FindAsync(user, password).Result;
    if (userIdentity != null)
    {
        var identity = new ClaimsIdentity(IdentityConfig.OAuthBearerOptions.AuthenticationType);
        identity.AddClaim(new Claim(ClaimTypes.Name, user));
        identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, userIdentity.Id));
        AuthenticationTicket ticket = new AuthenticationTicket(identity, new AuthenticationProperties());
        var currentUtc = new SystemClock().UtcNow;
        ticket.Properties.IssuedUtc = currentUtc;
        ticket.Properties.ExpiresUtc = currentUtc.Add(TimeSpan.FromMinutes(30));
        string AccessToken = IdentityConfig.OAuthBearerOptions.AccessTokenFormat.Protect(ticket);
        return AccessToken;
    }
    return "failed";
}

[HttpGet]
[Authorize]
[ActionName("Logout")]
public String Logout()
{
    var owinContext = HttpContext.Current.GetOwinContext();
    owinContext.Authentication.SignOut(DefaultAuthenticationTypes.ApplicationCookie, DefaultAuthenticationTypes.ExternalBearer);

    return "OK";
}

The Authenticate-method works well. My webapp gets a token from the request which I can set as an Authorization-header (e.g. in $http for angular apps). Subsequent calls to a [Authorize]-annotated function will return correctly. However, if I call Logout, it will return the "OK" string correctly, but doesn't invalidate the token. If I call a Authorize-method after calling Logout, I still get a correct value and not the expected 401 - Unauthorized.

  • I've seen this post: ASP.Net Identity Logout and tried the Signout without parameters. That doesn't work either.
  • HttpContext doesn't have the GetOwinContext. It's in HttpContext.Current in my case. Am I doing something wrong?
  • Why is my Logout Method not working?
1

1 Answers

8
votes

It seems like I got the basic concept of (bearer) tokens wrong and that's why it is not working. I leave this here in case somebody stumbles over the same problem:

Tokens can't be revoked or invalidated - at least not with ASP.NET Identity 2.0. The SignOut does not work for those kinds of authentications.

A solution for this are so called refresh tokens. There's currently no default implementation in Identity 2.0 or OWIN. But I found two blog posts with a solution: