jasdefer jasdefer - 17 days ago 7
C# Question

Cookie Authentication Asp.Net Core

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
ITicketStore
as 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.

Answer

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)
    {
        var options = new MemoryCacheEntryOptions();
        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);
    }
}
Comments