3

I'm generating and validating a JWT with the following code.

static string GenerateToken()
{
    var tokenHandler = new JwtSecurityTokenHandler();
    var certificate = new X509Certificate2(@"Test.pfx", "123");
    var rsa = certificate.GetRSAPrivateKey();

    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(),
        Issuer = "Self",
        IssuedAt = DateTime.Now,
        Audience = "Others",
        Expires = DateTime.MaxValue,
        SigningCredentials = new SigningCredentials(
            new RsaSecurityKey(rsa),
            SecurityAlgorithms.RsaSha256Signature)
    };

    var token = tokenHandler.CreateToken(tokenDescriptor);
    return tokenHandler.WriteToken(token);
}

static bool ValidateToken(string token)
{
    var tokenHandler = new JwtSecurityTokenHandler();
    var certificate = new X509Certificate2(@"Test.cer");
    var rsa = certificate.GetRSAPublicKey();

    var validationParameters = new TokenValidationParameters
    {
        ValidAudience = "Others",
        ValidIssuer = "Self",
        IssuerSigningKey = new RsaSecurityKey(rsa)
    };

    var principal = tokenHandler.ValidateToken(token, validationParameters, out SecurityToken securityToken);
    if (principal == null)
        return false;
    if (securityToken == null)
        return false;

    return true;
}

I have this code in a library which targets .net standard 2.0 and net46.

When I use the library in an .net core app 2.0 project everything is working as expected. I use the following nuget packages.

  • System.IdentityModel.Tokens.Jwt => 5.1.4
  • System.Security.Cryptography.Csp => 4.3.0

But when I build the same code with .net46 I get the following exception when trying to generate a token.

var token = tokenHandler.CreateToken(tokenDescriptor);

System.NotSupportedException: 'NotSupported_Method'

The the following exception is throw when I try to validate a token.

var principal = tokenHandler.ValidateToken(token, validationParameters, out SecurityToken securityToken);

Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: 'IDX10503: Signature validation failed. Keys tried: 'Microsoft.IdentityModel.Tokens.RsaSecurityKey , KeyId: '.

NtFreX
  • 10,379
  • 2
  • 43
  • 63

2 Answers2

5

Instead of using an RsaSecurityKey I directly use an X509SecurityKey now. This works for both netstandard2.0 and net46.

static string GenerateToken()
{
    var tokenHandler = new JwtSecurityTokenHandler();
    var certificate = new X509Certificate2(@"Test.pfx", "123");
    var securityKey = new X509SecurityKey(certificate);

    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(),
        Issuer = "Self",
        IssuedAt = DateTime.Now,
        Audience = "Others",
        Expires = DateTime.MaxValue,
        SigningCredentials = new SigningCredentials(
            securityKey,
            SecurityAlgorithms.RsaSha256Signature)
    };

    var token = tokenHandler.CreateToken(tokenDescriptor);
    return tokenHandler.WriteToken(token);
}

static bool ValidateToken(string token)
{
    var tokenHandler = new JwtSecurityTokenHandler();
    var certificate = new X509Certificate2(@"Test.cer");
    var securityKey = new X509SecurityKey(certificate);

    var validationParameters = new TokenValidationParameters
    {
        ValidAudience = "Others",
        ValidIssuer = "Self",
        IssuerSigningKey = securityKey
    };

    var principal = tokenHandler.ValidateToken(token, validationParameters, out SecurityToken securityToken);
    if (principal == null)
        return false;
    if (securityToken == null)
        return false;

    return true;
}

Also I only need the System.IdentityModel.Tokens.Jwt nuget package and can remove the System.Security.Cryptography.Csp package.

NtFreX
  • 10,379
  • 2
  • 43
  • 63
0

Thank you NtFrex ..

I just put minor changes to NtFrex's answer to make it work for me. And this works with .net 4.5.1 as well & I thought it might help someone. Here is the final code but first create a certificate. I've used openssl to create one with RSA512.

Create Token :

    private string GenerateToken1()
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var certificate = new X509Certificate2(@"C:\Users\myname\my-cert.pfx", "mypassword");
        var securityKey = new X509SecurityKey(certificate);

        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(),
            Issuer = "Self",
            IssuedAt = DateTime.Now,
            Audience = "Others",
            Expires = DateTime.Now.AddMinutes(30),
            SigningCredentials = new SigningCredentials(
                securityKey,
                SecurityAlgorithms.RsaSha512Signature)
        };

        var token = tokenHandler.CreateToken(tokenDescriptor);
        return tokenHandler.WriteToken(token);
    }

Validate Token :

    private bool ValidateToken1(string token)
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var certificate = new X509Certificate2(@"C:\Users\myname\my-cert.pfx", "mypassword");
        var securityKey = new X509SecurityKey(certificate);

        var validationParameters = new TokenValidationParameters
        {
            ValidAudience = "Others",
            ValidIssuer = "Self",
            IssuerSigningKey = securityKey
        };

        SecurityToken securityToken;
        var principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);
        if (principal == null)
            return false;
        if (securityToken == null)
            return false;

        return true;
    }
Rakesh
  • 97
  • 8
  • You can use a pfx file to validate a token but the `pfx` file contains both the private and public key. You only need the public key for validation. The `cer` file is a container which contains only the public key. [Here](https://stackoverflow.com/questions/403174/convert-pfx-to-cer) is a little description how you can convert your `pfx` file to an `cer` file. – NtFreX Aug 24 '18 at 10:53
  • True. Thank you. This way token can be generated at one place/app and can be validated at multiple places/app as well. That way you can give the .cer file to multiple other app you trust. Kind of Identity provider creates it and the Service Provider validates it. My wild imagination. Thank you, Rakesh – Rakesh Aug 30 '18 at 10:03