NtFreX
NtFreX

Reputation: 11357

JWT generation and validation in .net throws "Key is not supported"

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.

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: '.

Upvotes: 3

Views: 8083

Answers (2)

Rakesh
Rakesh

Reputation: 117

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;
    }

Upvotes: 0

NtFreX
NtFreX

Reputation: 11357

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.

Upvotes: 5

Related Questions