Extracting Bearer Token from OWIN Cookie

Home / Extracting Bearer Token from OWIN Cookie

If you’ll recall a previous post in which I examined decrypting the OWIN AuthenticationTicket, I didn’t really examine how to deal with the ticket in the context of cookies.


OWIN cookies are interesting. Essentially, the encrypted value of the cookie is the AuthenticationTicket. The encrypted AuthenticationTicket is also the Bearer token. Therefore, if we can can get to the AuthenticationTicket, and encrypt it, we can make requests to other systems or services on the user’s behalf. This is convenient in working with disparate systems that share authorization/authentication.

Going directly to the request headers, imho, is the easiest method to access the cookie. Once we have the cookie, we need to instantiate an IDataProtector with Protect/Unprotect methods implemented. In my previous post, I left the Protect method unimplemented since I had no use for it at the time.

Taking a page from my previous post, we only need to provide the correct “purpose” for the decryption to work. I had to clone the Katana source from github in order to determine what this should be for cookie decrypting. Decrypting the cookie has a different purpose than “Access_Token,” as was the case in my other post. To accommodate the cookie decryption, and to handle encryption, I simply expanded my IDataProtector to provide the correct purposes for both Access_Token access and Cookie access:

/// <summary>
/// Helper method to decrypt the OWIN ticket
/// </summary>
public class MachineKeyProtector : IDataProtector
{
    private string[] _purpose;

    private string[] _accessTokenPurpose = 
    {
        typeof(OAuthAuthorizationServerMiddleware).Namespace,
        "Access_Token",
        "v1"
    };

    private string[] _cookiePurpose = {
        typeof(CookieAuthenticationMiddleware).FullName,
        SSOSettings.AuthenticationType,
        "v1"
    };

    public MachineKeyProtector()
    {
        _purpose = _accessTokenPurpose;
    }

    public MachineKeyProtector(string purpose)
    {
        if (purpose == "cookie")
        {
            _purpose = _cookiePurpose;
        }
        else
        {
            _purpose = _accessTokenPurpose;
        }
    }

    public byte[] Protect(byte[] userData)
    {
        return System.Web.Security.MachineKey.Protect(userData, _purpose);
    }

    public byte[] Unprotect(byte[] protectedData)
    {
        return System.Web.Security.MachineKey.Unprotect(protectedData, _purpose);
    }
}

One thing you’ll notice is that my authentication type is configuration driven for cookie authentication. This has to match our CookieAuthenticationOptions or else encryption/decryption will fail with crypto exceptions.

With this bit of code in place, I created a simple method that will extract the cookie (ticket) from the request header and return the unencrypted AuthenticationTicket:

public static AuthenticationTicket GetAuthenticationTicketFromCookie()
{
    var configSettings = SSOSettings.Config;
    var cookieName = string.IsNullOrWhiteSpace(configSettings.CookieSettings.Name) ?
        string.Format("{0}{1}", CookieAuthenticationDefaults.CookiePrefix, CookieAuthenticationDefaults.AuthenticationType) :
        configSettings.CookieSettings.Name;
    var cookie = HttpContext.Current.Request.Cookies.Get(cookieName);
    var ticket = cookie.Value;
    // Deal with URL encoding
    ticket = ticket.Replace('-', '+').Replace('_', '/');
    var padding = 3 - ((ticket.Length + 3) % 4);
    if (padding != 0) { ticket = ticket + new string('=', padding); }
    var secureDataFormat = new TicketDataFormat(new MachineKeyProtector("cookie"));
    return secureDataFormat.Unprotect(ticket);
}

As with the “purposes” the cookie name is configurable, so I account for that based on my own configuration settings. If I haven’t specified a cookie name, I sue OWIN’s default naming to find the cookie. Once the cookie is in hand, it must be URL decoded and padded. Once we accomplish that, we can use our IDataProtecter and OWIN’s TicketDataFormat to get a handle to the secure data format’s Unprotect method. At that point, we unprotect, or decrypt, the ticket and receive an AuthenticationTicket object. The AuthenticationTicket contains the IIdentity and all of its claims. In order to convert this to a bearer token, we must encrypt it with the purpose of “Access_Token.”

public static string GetBearerTokenFromCookie()
{
    var ticket = GetAuthenticationTicketFromCookie();
    var secureDataFormat = new TicketDataFormat(new MachineKeyProtector());
    var encryptedToken = secureDataFormat.Protect(ticket);
    return string.Format("Bearer {0}", encryptedToken);
}

Finally, with that token in hand we can simply simple add the bearer token as needed and make our requests on the user’s behalf. Something like this works:

var requestMessage = new HttpRequestMessage()
{
    RequestUri = requestUri,
    Method = HttpMethod.Get
};

var bearerToken = GetBearerTokenFromCookie();
requestMessage.Headers.Add("Authorization", bearerToken);

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.