Securing the JWT with a X509Certificate2 (JwtSecurityTokenHandler)

tugberk picture tugberk · Aug 3, 2013 · Viewed 11.6k times · Source

I managed to make the JwtSecurityTokenHandler work with X509Certificate2. I was able to sign the token with a X509Certificate2 object. I was also able to validate the token by using the certificate's raw data through X509Certificate2.RawData property.

Here is the code:

class Program
{
    static void Main(string[] args)
    {
        X509Store store = new X509Store("My");
        store.Open(OpenFlags.ReadOnly);
        X509Certificate2 signingCert = store.Certificates[0];

        string token = CreateTokenWithX509SigningCredentials(signingCert);
        ClaimsPrincipal principal = ValidateTokenWithX509SecurityToken(
            new X509RawDataKeyIdentifierClause(signingCert.RawData), token);
    }

    static string CreateTokenWithX509SigningCredentials(X509Certificate2 signingCert)
    {
        var now = DateTime.UtcNow;
        var tokenHandler = new JwtSecurityTokenHandler();
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new Claim[]
                    {
                        new Claim(ClaimTypes.Name, "Tugberk"),
                        new Claim(ClaimTypes.Role, "Sales"), 
                    }),
            TokenIssuerName = "self",
            AppliesToAddress = "http://www.example.com",
            Lifetime = new Lifetime(now, now.AddMinutes(2)),
            SigningCredentials = new X509SigningCredentials(signingCert)
        };

        SecurityToken token = tokenHandler.CreateToken(tokenDescriptor);
        string tokenString = tokenHandler.WriteToken(token);

        return tokenString;
    }

    static ClaimsPrincipal ValidateTokenWithX509SecurityToken(X509RawDataKeyIdentifierClause x509DataClause, string token)
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var x509SecurityToken = new X509SecurityToken(new X509Certificate2(x509DataClause.GetX509RawData()));
        var validationParameters = new TokenValidationParameters()
        {
            AllowedAudience = "http://www.example.com",
            SigningToken = x509SecurityToken,
            ValidIssuer = "self",
        };

        ClaimsPrincipal claimsPrincipal = tokenHandler.ValidateToken(
            new JwtSecurityToken(token), validationParameters);

        return claimsPrincipal;
    }
}

My main question is all about what should I expose to the world from my X509Certificate2. Which part of the X509Certificate2 should I reveal so that the consumer should validate the JWT token but cannot create a new token using the same certificate?

Answer

woloski picture woloski · Aug 3, 2013

You have to expose the public key which you can get by right clicking on the certificate and do Export (dont include the private key) on the MMC. Then whoever has to validate the token would do

 var x509 = new X509Certificate2(pathToExportedCert);

Or you can also use the byte array ctor and have the public key encoded in base64.