Being able to decrypt the OWIN AuthenticationTicket can be very useful. In the cases where the cookie/tickets are shared across applications, this is especially true.
Interestingly, if you’re using OWIN for both cookie-based authentication and access tokens, the Ticket is stored in both mediums.
With that in mind, the easiest method to decrypt a ticket to access claims, etc is to simply stand up a protected Resource server with a single Api endpoint to display the contents of the ticket. Going this route, the decryption is automatically handled by OWIN with very little code. The endpoint can be accessed by a user’s browser (decrypting the cookie) or by a server passing in a Bearer token.
Here’s an example that simply displays all of the user’s claims from either an AccessToken or Cookie:
// Allow CORS for all origins. [EnableCors(origins: "*", headers: "*", methods: "*")] [HostAuthentication("Application")] [Authorize] public class UserController : ApiController { public object Get() { var identity = this.User.Identity as ClaimsIdentity; var roleClaims = identity.Claims.Where(x => x.Type == ClaimsIdentity.DefaultRoleClaimType).Select(x => x.Value).ToList(); var nonRoleClaims = identity.Claims.Where(x => x.Type != ClaimsIdentity.DefaultRoleClaimType).Select(x => new { Type = x.Type, Value = x.Value }).ToList(); return new { name = identity.Name, roles = roleClaims, claims = nonRoleClaims }; } }
In the case where we’re designing an SSO system, in which multiple applications are sharing the auth cookie and machineKeys, which OWIN uses for encryption/decryption, and also hooking into the Middleware, we can decrypt the Access Token returned from the authorization code flow directly. To accomplish this, we implement the IDataProtector interface and use the System.Web.Security.MachineKey.Unprotect method.
/// <summary> /// Helper method to decrypt the OWIN ticket /// </summary> private class MachineKeyProtector : IDataProtector { private readonly string[] _purpose = { typeof(OAuthAuthorizationServerMiddleware).Namespace, "Access_Token", "v1" }; public byte[] Protect(byte[] userData) { throw new NotImplementedException(); } public byte[] Unprotect(byte[] protectedData) { return System.Web.Security.MachineKey.Unprotect(protectedData, _purpose); } }
To utilize this, we just create an instance and pass in the Token to get the decrypted Ticket:
var secureDataFormat = new TicketDataFormat(new MachineKeyProtector()); AuthenticationTicket ticket = secureDataFormat.Unprotect(accessToken);
The AuthenticationTicket itself contains the ClaimsIdentity and a Dictionary of Properties. This can be useful for a number of things from testing to hooking into the MiddleWare and creating our own local ticket/cookie without the need to go back against the protected Resource provider.
On a side note, I did notice that the version of OWIN across machines has to match. IE – I had one application running OWIN v3 and another running v2. They could neither decrypt the tickets between them nor utilize the shared domain cookie.
Thanks for this amazing post this is what I have been looking for. In my case, I have an identity framework hosted on Azure and I want to decode the generated token in other applications that may or not live in azure as well. do you have a sample code you can share? I’m kind of lost on where to implement your solution
Sure – Here’s an example where I requested a token from the OWIN server using password grant flow. The response is decrypted using the MachineKeyProtector as described in the post. Note that if you’re using the newer .NET Core DataProtector, the decryption is slightly different since the DataProtectorShim class must be used.
Why on Deploy… IIS
AuthenticationTicket ticket = secureDataFormat.Unprotect(accessToken);
Return null object always?
I’m not sure why that would always be null. My only thought is that your token is empty or the purposes are not matching between server/client.
Thank you very much ! I wonder how did you get to know what to set in the purpose ? Is it documented somewhere or you had to lookup in OWIN source code ?
It is kinda/sorta documented if you look into MachineKey class and its methods. The only thing mentioned is that the purpose has to be the same used between a protect/unprotect flow. So, it behaves like a key in the encryption.
https://docs.microsoft.com/en-us/dotnet/api/system.web.security.machinekey?view=netframework-4.7.2
Hi, I need to wrap a legacy system that uses this kind of token, do you know if there is a way to decrypt it using Java? Thanks!
Hi,
I am using the same code in asp.net and passing 256 character token but getting exception ‘ Error occurred during a cryptographic operation ‘
Using exact code shared above, do I need to add anything else, like notifying machine key in web.config or something.
Having the machineKey in the web.config is my first thought as to what would fix this. For the .NET (non-Core) projects where I used this, I always had a machineKey node in the web.config and things worked fine.