How to manually decrypt an ASP.NET Core Authentication cookie?
While inside ASP.NET Core app you can just use CookieAuthenticationOptions.TicketDataFormat.Unprotect(cookieValue)
.
Here, a simple static (!) method I wrote:
public static AuthenticationTicket DecryptAuthCookie(HttpContext httpContext)
{
// ONE - grab the CookieAuthenticationOptions instance
var opt = httpContext.RequestServices
.GetRequiredService<IOptionsMonitor<CookieAuthenticationOptions>>()
.Get(CookieAuthenticationDefaults.AuthenticationScheme); //or use .Get("Cookies")
// TWO - Get the encrypted cookie value
var cookie = opt.CookieManager.GetRequestCookie(httpContext, opt.Cookie.Name);
// THREE - decrypt it
return opt.TicketDataFormat.Unprotect(cookie);
}
Works fine under .NET 5 and .NET 6.
I'm adding this answer for reference, because this question pops up on every search engine if you search for how to manually decrypt ASP.NET auth cookie.
See below a helper method for .NET Core 2 to get claims from a cookie:
private IEnumerable<Claim> GetClaimFromCookie(HttpContext httpContext, string cookieName, string cookieSchema)
{
// Get the encrypted cookie value
var opt = httpContext.RequestServices.GetRequiredService<IOptionsMonitor<CookieAuthenticationOptions>>();
var cookie = opt.CurrentValue.CookieManager.GetRequestCookie(httpContext, cookieName);
// Decrypt if found
if (!string.IsNullOrEmpty(cookie))
{
var dataProtector = opt.CurrentValue.DataProtectionProvider.CreateProtector("Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", cookieSchema, "v2");
var ticketDataFormat = new TicketDataFormat(dataProtector);
var ticket = ticketDataFormat.Unprotect(cookie);
return ticket.Principal.Claims;
}
return null;
}
As was pointed by @Cirem, the dodgy way of creating a protector is exactly how Microsoft does it (see their code here). Therefore, it may change in future versions.
Decrypting the Authentication Cookie without needing the keys
It's worth noting that you don't need to gain access to the keys to decrypt the authentication cookie. You simply need to use the right IDataProtector
created with the right purpose parameter, and subpurpose parameters.
Based on the CookieAuthenticationMiddleware
source code https://github.com/aspnet/Security/blob/rel/1.1.1/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationMiddleware.cs#L4 it looks like the purpose you need to pass is typeof(CookieAuthenticationMiddleware)
. And since they are passing additional parameters to the IDataProtector
you will need to match them. So this line of code should get you an IDataProtector
that can be used to decrypt the authentication cookie:
var dataProtector = provider.CreateProtector(typeof(CookieAuthenticationMiddleware).FullName, Options.AuthenticationScheme, "v2");
Note thatOptions.AuthenticationScheme
is just "MyCookie" in this case since that's what it was set to in the Configure
method of the startup.cs file.
Here is an example action method for decrypting your authentication cookie two different ways:
public IActionResult DecryptCookie() {
//Get the encrypted cookie value
string cookieValue = HttpContext.Request.Cookies["MyCookie"];
//Get a data protector to use with either approach
var dataProtector = provider.CreateProtector(typeof(CookieAuthenticationMiddleware).FullName, "MyCookie", "v2");
//Get the decrypted cookie as plain text
UTF8Encoding specialUtf8Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
byte[] protectedBytes = Base64UrlTextEncoder.Decode(cookieValue);
byte[] plainBytes = dataProtector.Unprotect(protectedBytes);
string plainText = specialUtf8Encoding.GetString(plainBytes);
//Get the decrypted cookie as a Authentication Ticket
TicketDataFormat ticketDataFormat = new TicketDataFormat(dataProtector);
AuthenticationTicket ticket = ticketDataFormat.Unprotect(cookieValue);
return View();
}
This method uses an IDataProtectionProvider
called provider
that is constructor injected.
Decrypting the Authentication Cookie when persisting keys to a directory
If you want to share cookies between applications then you might decide to persist the data protection keys to a directory. This can be done by adding the following to the ConfigureServices
method of the startup.cs file:
services.AddDataProtection().PersistKeysToFileSystem(
new DirectoryInfo(@"C:\temp-keys\"));
BE CAREFUL though because the keys are not encrypted so it's up to you to protect them!!! Only persist the keys to a directory if you absolutely must, (or if you are just trying to understand how the system works). You will also need to specify a cookie DataProtectionProvider
that uses those keys. This can be done with the help of the UseCookieAuthentication
configuration in the Configure
method of the startup.cs class like so:
app.UseCookieAuthentication(new CookieAuthenticationOptions() {
DataProtectionProvider = DataProtectionProvider.Create(new DirectoryInfo(@"C:\temp-keys\")),
AuthenticationScheme = "MyCookie",
CookieName = "MyCookie",
LoginPath = new PathString("/Home/Login"),
AccessDeniedPath = new PathString("/Home/AccessDenied"),
AutomaticAuthenticate = true,
AutomaticChallenge = true
});
With that configuration done. You can now decrypt the authentication cookie with the following code:
public IActionResult DecryptCookie() {
ViewData["Message"] = "This is the decrypt page";
var user = HttpContext.User; //User will be set to the ClaimsPrincipal
//Get the encrypted cookie value
string cookieValue = HttpContext.Request.Cookies["MyCookie"];
var provider = DataProtectionProvider.Create(new DirectoryInfo(@"C:\temp-keys\"));
//Get a data protector to use with either approach
var dataProtector = provider.CreateProtector(typeof(CookieAuthenticationMiddleware).FullName, "MyCookie", "v2");
//Get the decrypted cookie as plain text
UTF8Encoding specialUtf8Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
byte[] protectedBytes = Base64UrlTextEncoder.Decode(cookieValue);
byte[] plainBytes = dataProtector.Unprotect(protectedBytes);
string plainText = specialUtf8Encoding.GetString(plainBytes);
//Get teh decrypted cookies as a Authentication Ticket
TicketDataFormat ticketDataFormat = new TicketDataFormat(dataProtector);
AuthenticationTicket ticket = ticketDataFormat.Unprotect(cookieValue);
return View();
}
You can learn more about this latter scenario here: https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/compatibility/cookie-sharing