Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 275
jasdefer Avatar asked Nov 16 '16 10:11

jasdefer


People also ask

What is cookie authentication in ASP.NET Core?

ASP.NET Core provides a cookie authentication mechanism which on login serializes the user details in form of claims into an encrypted cookie and then sends this cookie back to the server on subsequent requests which gets validated to recreate the user object from claims and sets this user object in the HttpContext so ...

What is cookie authentication?

Cookie authentication uses HTTP cookies to authenticate client requests and maintain session information. It works as follows: The client sends a login request to the server.

What is HttpContext SignInAsync?

SignInAsync(HttpContext, ClaimsPrincipal) Sign in a principal for the default authentication scheme. The default scheme for signing in can be configured using DefaultSignInScheme. SignInAsync(HttpContext, ClaimsPrincipal, AuthenticationProperties) Sign in a principal for the default authentication scheme.

What is SameSite cookie .NET Core?

SameSite is an IETF draft standard designed to provide some protection against cross-site request forgery (CSRF) attacks. Originally drafted in 2016, the draft standard was updated in 2019.


1 Answers

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);
    }
}
like image 127
David Pine Avatar answered Oct 03 '22 06:10

David Pine