9

Can I use MemoryCache in an ITicketStore to store an AuthenticationTicket?

Background: My web app is using Cookie Authentication:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AutomaticAuthenticate = true,
    AutomaticChallenge = true,
    LoginPath = new PathString("/Authentication/SignIn"),
    LogoutPath = new PathString("/Authentication/SignOut"),
    ReturnUrlParameter = "/Authentication/SignIn"
});

My web api handles the authorization process using access tokens (OAuth2).

Sometimes (on some browsers) the following exception is thrown:

An unhandled exception has occurred: The chunked cookie is incomplete. Only 1 of the expected 2 chunks were found, totaling 4021 characters. A client size limit may have been exceeded.

The cookie is obviously too big. This is strange, because I don't use many claims. All of them are default claims (nameidentifier, nonce, exp, etc.). I am now trying to implement my own ITicketStoreas a SessionStore on the CookieAuthenticationOptions. The AuthenticationTicket will be stored in a MemoryCache (like in this sample). I am very new to this whole topic and not sure, if this is a good approach and if the MemoryCache is a valid solution.

1

1 Answer 1

11

Can I use MemoryCache in an ITicketStore to store an AuthenticationTicket?

Absolutely, here is the implementation that I have been using for nearly a year.

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationScheme = "App.Cookie",
    AutomaticAuthenticate = true,
    AutomaticChallenge = true,
    LoginPath = new PathString("/Authentication/SignIn"),
    LogoutPath = new PathString("/Authentication/SignOut"),
    ReturnUrlParameter = "/Authentication/SignIn",
    SessionStore = new MemoryCacheStore(cache)
});

The implementation of the MemoryCacheStore looks like this, and it followed the example that you shared:

public class MemoryCacheStore : ITicketStore
{
    private const string KeyPrefix = "AuthSessionStore-;
    private readonly IMemoryCache _cache;

    public MemoryCacheStore(IMemoryCache cache)
    {
        _cache = cache;
    }

    public async Task<string> StoreAsync(AuthenticationTicket ticket)
    {
        var key = KeyPrefix + Guid.NewGuid();
        await RenewAsync(key, ticket);
        return key;
    }

    public Task RenewAsync(string key, AuthenticationTicket ticket)
    {
        // https://github.com/aspnet/Caching/issues/221
        // Set to "NeverRemove" to prevent undesired evictions from gen2 GC
        var options = new MemoryCacheEntryOptions
        {
            Priority = CacheItemPriority.NeverRemove
        };
        var expiresUtc = ticket.Properties.ExpiresUtc;

        if (expiresUtc.HasValue)
        {
            options.SetAbsoluteExpiration(expiresUtc.Value);
        }    

        options.SetSlidingExpiration(TimeSpan.FromMinutes(60));

        _cache.Set(key, ticket, options);

        return Task.FromResult(0);
    }

    public Task<AuthenticationTicket> RetrieveAsync(string key)
    {
        AuthenticationTicket ticket;
        _cache.TryGetValue(key, out ticket);
        return Task.FromResult(ticket);
    }

    public Task RemoveAsync(string key)
    {
        _cache.Remove(key);
        return Task.FromResult(0);
    }
}
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks for the reply. Has this approach any disadvantages compared to using cookies? The web app can run out of memory is the only thing I can think of.
It is actually using cookies, hence the UseCookieAuthentication. If memory is a concern consider the fact that these expire and will fallout of memory once expired, as they'll be released and cleaned up. Additionally, they are tiny...likewise, depending on how you are setup to host the application can determine whether or not it will ever have an impact. You'd want to be able to scale.
No memory is not really a concern. I was just thinking about general disadvantages. Yeah, it uses cookies, but the AuthenticationTicket itself is not stored in a cookie, only the reference is. Is this correct?
Incorrect, everything in the cookie gets deserialized into a ClaimsPrinicipal .. and that principle is what makes up the AuthenticationTicket github.com/aspnet/Security/blob/….
Ah okay, that makes sense. But something must be stored locally for the user? Maybe the key returning from the StoreAsync method? Or how does the server recognizes the user?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.