Verifying JWT signed with the RS256 algorithm using public key in C#

76,062

Solution 1

Thanks to jwilleke, I have got a solution. To verify the RS256 signature of a JWT, it is needed to use the RSAPKCS1SignatureDeformatter class and its VerifySignature method.

Here is the exact code for my sample data:

  string tokenStr = "eyJraWQiOiIxZTlnZGs3IiwiYWxnIjoiUlMyNTYifQ.ewogImlzcyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZfV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5NzAsCiAiY19oYXNoIjogIkxEa3RLZG9RYWszUGswY25YeENsdEEiCn0.XW6uhdrkBgcGx6zVIrCiROpWURs-4goO1sKA4m9jhJIImiGg5muPUcNegx6sSv43c5DSn37sxCRrDZZm4ZPBKKgtYASMcE20SDgvYJdJS0cyuFw7Ijp_7WnIjcrl6B5cmoM6ylCvsLMwkoQAxVublMwH10oAxjzD6NEFsu9nipkszWhsPePf_rM4eMpkmCbTzume-fzZIi5VjdWGGEmzTg32h3jiex-r5WTHbj-u5HL7u_KP3rmbdYNzlzd1xWRYTUs4E8nOTgzAUwvwXkIQhOh5TPcSMBYy6X3E7-_gr9Ue6n4ND7hTFhtjYs3cjNKIA08qm5cpVYFMFMG6PkhzLQ";
  string[] tokenParts = tokenStr.Split('.');

  RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
  rsa.ImportParameters(
    new RSAParameters() {
      Modulus = FromBase64Url("w7Zdfmece8iaB0kiTY8pCtiBtzbptJmP28nSWwtdjRu0f2GFpajvWE4VhfJAjEsOcwYzay7XGN0b-X84BfC8hmCTOj2b2eHT7NsZegFPKRUQzJ9wW8ipn_aDJWMGDuB1XyqT1E7DYqjUCEOD1b4FLpy_xPn6oV_TYOfQ9fZdbE5HGxJUzekuGcOKqOQ8M7wfYHhHHLxGpQVgL0apWuP2gDDOdTtpuld4D2LK1MZK99s9gaSjRHE8JDb1Z4IGhEcEyzkxswVdPndUWzfvWBBWXWxtSUvQGBRkuy1BHOa4sP6FKjWEeeF7gm7UMs2Nm2QUgNZw6xvEDGaLk4KASdIxRQ"),
      Exponent = FromBase64Url("AQAB")
    });

  SHA256 sha256 = SHA256.Create();
  byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(tokenParts[0] + '.' + tokenParts[1]));

  RSAPKCS1SignatureDeformatter rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
  rsaDeformatter.SetHashAlgorithm("SHA256");
  if (rsaDeformatter.VerifySignature(hash, FromBase64Url(tokenParts[2])))
    MessageBox.Show("Signature is verified");

//...
  static byte[] FromBase64Url(string base64Url)
  {
    string padded = base64Url.Length % 4 == 0
        ? base64Url : base64Url + "====".Substring(base64Url.Length % 4);
    string base64 = padded.Replace("_", "/")
                          .Replace("-", "+");
    return Convert.FromBase64String(base64);
  }

Solution 2

Here is an example using IdentityModel.Tokens.Jwt for validation:

string tokenStr = "eyJraWQiOiIxZTlnZGs3IiwiYWxnIjoiUlMyNTYifQ.ewogImlzcyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZfV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5NzAsCiAiY19oYXNoIjogIkxEa3RLZG9RYWszUGswY25YeENsdEEiCn0.XW6uhdrkBgcGx6zVIrCiROpWURs-4goO1sKA4m9jhJIImiGg5muPUcNegx6sSv43c5DSn37sxCRrDZZm4ZPBKKgtYASMcE20SDgvYJdJS0cyuFw7Ijp_7WnIjcrl6B5cmoM6ylCvsLMwkoQAxVublMwH10oAxjzD6NEFsu9nipkszWhsPePf_rM4eMpkmCbTzume-fzZIi5VjdWGGEmzTg32h3jiex-r5WTHbj-u5HL7u_KP3rmbdYNzlzd1xWRYTUs4E8nOTgzAUwvwXkIQhOh5TPcSMBYy6X3E7-_gr9Ue6n4ND7hTFhtjYs3cjNKIA08qm5cpVYFMFMG6PkhzLQ";

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(
  new RSAParameters()
  {
      Modulus = FromBase64Url("w7Zdfmece8iaB0kiTY8pCtiBtzbptJmP28nSWwtdjRu0f2GFpajvWE4VhfJAjEsOcwYzay7XGN0b-X84BfC8hmCTOj2b2eHT7NsZegFPKRUQzJ9wW8ipn_aDJWMGDuB1XyqT1E7DYqjUCEOD1b4FLpy_xPn6oV_TYOfQ9fZdbE5HGxJUzekuGcOKqOQ8M7wfYHhHHLxGpQVgL0apWuP2gDDOdTtpuld4D2LK1MZK99s9gaSjRHE8JDb1Z4IGhEcEyzkxswVdPndUWzfvWBBWXWxtSUvQGBRkuy1BHOa4sP6FKjWEeeF7gm7UMs2Nm2QUgNZw6xvEDGaLk4KASdIxRQ"),
      Exponent = FromBase64Url("AQAB")
  });

var validationParameters = new TokenValidationParameters
                {
                    RequireExpirationTime = true,
                    RequireSignedTokens = true,
                    ValidateAudience = false,
                    ValidateIssuer = false,
                    ValidateLifetime = false,
                    IssuerSigningKey = new RsaSecurityKey(rsa)
                };

SecurityToken validatedSecurityToken = null;
var handler = new JwtSecurityTokenHandler();
handler.ValidateToken(tokenStr, validationParameters, out validatedSecurityToken);
JwtSecurityToken validatedJwt = validatedSecurityToken as JwtSecurityToken;

Solution 3

For anyone that is looking for a quick method to validate RS256 with a public key that has "-----BEGIN PUBLIC KEY-----"/"-----END PUBLIC KEY------"

Here are two methods with the help of BouncyCastle.

    public bool ValidateJasonWebToken(string fullKey, string jwtToken)
    {
        try
        {
            var rs256Token = fullKey.Replace("-----BEGIN PUBLIC KEY-----", "");
            rs256Token = rs256Token.Replace("-----END PUBLIC KEY-----", "");
            rs256Token = rs256Token.Replace("\n", "");

            Validate(jwtToken, rs256Token);
            return true;
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            return false;
        }
    }

    private void Validate(string token, string key)
    {
        var keyBytes = Convert.FromBase64String(key); // your key here

        AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes);
        RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
        RSAParameters rsaParameters = new RSAParameters
        {
            Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned(),
            Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned()
        };
        using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
        {
            rsa.ImportParameters(rsaParameters);
            var validationParameters = new TokenValidationParameters()
            {
                RequireExpirationTime = false,
                RequireSignedTokens = true,
                ValidateAudience = false,
                ValidateIssuer = false,
                IssuerSigningKey = new RsaSecurityKey(rsa)
            };
            var handler = new JwtSecurityTokenHandler();
            var result = handler.ValidateToken(token, validationParameters, out var validatedToken);
        }
    }

This is a combination of http://codingstill.com/2016/01/verify-jwt-token-signed-with-rs256-using-the-public-key/ and @olaf answer that uses system.IdentityModel.Tokens.Jwt

Solution 4

NET Core

To use this in a .NET core web api (.NET Framework see below) in a AddJwtBearer() auth flow I enhanced NvMat's great answer:

Very important is to not use the RSACryptoServiceProvider in an using statement.

    private TokenValidationParameters GetTokenValidationParameters(string key)
    {
        var rs256Token = key.Value.Replace("-----BEGIN PUBLIC KEY-----", "");
        rs256Token = rs256Token.Replace("-----END PUBLIC KEY-----", "");
        rs256Token = rs256Token.Replace("\n", "");

        var keyBytes = Convert.FromBase64String(rs256Token);

        var asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes);
        var rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
        var rsaParameters = new RSAParameters
        {
            Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned(),
            Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned()
        };
        var rsa = new RSACryptoServiceProvider();

        rsa.ImportParameters(rsaParameters);

        var validationParameters = new TokenValidationParameters()
        {
            RequireExpirationTime = false,
            RequireSignedTokens = true,
            ValidateAudience = false,
            ValidateIssuer = false,
            IssuerSigningKey = new RsaSecurityKey(rsa),
        };

        return validationParameters;
    }

Then you are able to use authentication in the startup like this:

services.AddAuthentication(x =>
{
    x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.RequireHttpsMetadata = false;
    options.SaveToken = true;
    options.IncludeErrorDetails = true;
    options.TokenValidationParameters = GetTokenValidationParameters(configuration["Key"]);
    options.Audience = configuration["ClientId"];
});

NET Framework

It is also possible to use this approach in a .NET Framework web api project. All you have to do is add this line to your startup Configure() method:

app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions()
{
     TokenValidationParameters = GetTokenValidationParameters(ConfigurationManager.AppSettings["Key"])
});

One important thing: Make sure you use a verion >=5.0.0 of the JwtSecurityTokenHandler I had problems with the 4.X.X versions.

Solution 5

.NET JWT Signature Verification using System.Security.Cryptography - No 3rd Party DLLs

var errorMessage = string.Empty;

// Google RSA well known Public Key data is available at https://accounts.google.com/.well-known/openid-configuration by navigating to the path described in the "jwks_uri" parameter.
// {
//     e: "AQAB",        // RSA Exponent
//     n: "ya_7gV....",  // RSA Modulus aka Well Known Public Key
//     alg: "RS256"      // RSA Algorithm
// }

var verified = VerifyJWT_RS256_Signature(
    jwt: "oicjwt....", 
    publicKey: "ya_7gV....", 
    exponent: "AQAB",
    errorMessage: out errorMessage);

if (!verified)
{
    // TODO: log error: 
    // TODO: Do something
}

NOTE: The following method verifies OpenID Connect JWT Signatures signed with Asymetric RS256 keys. OpenID Connect providers may opt to use other versions of Asymetric keys or even Symetric keys like HS256. This method does not directly support other key types.

public static bool VerifyJWT_RS256_Signature(string jwt, string publicKey, string exponent, out string errorMessage)
{
    if (string.IsNullOrEmpty(jwt))
    {
        errorMessage = "Error verifying JWT token signature: Javascript Web Token was null or empty.";
        return false;
    }

    var jwtArray = jwt.Split('.');
    if (jwtArray.Length != 3 && jwtArray.Length != 5)
    {
        errorMessage = "Error verifying JWT token signature: Javascript Web Token did not match expected format. Parts count was " + jwtArray.Length + " when it should have been 3 or 5.";
        return false;
    }

    if (string.IsNullOrEmpty(publicKey))
    {
        errorMessage = "Error verifying JWT token signature: Well known RSA Public Key modulus was null or empty.";
        return false;
    }

    if (string.IsNullOrEmpty(exponent))
    {
        errorMessage = "Error verifying JWT token signature: Well known RSA Public Key exponent was null or empty.";
        return false;
    }

    try
    {
        string publicKeyFixed = (publicKey.Length % 4 == 0 ? publicKey : publicKey + "====".Substring(publicKey.Length % 4)).Replace("_", "/").Replace("-", "+");
        var publicKeyBytes = Convert.FromBase64String(publicKeyFixed);

        var jwtSignatureFixed = (jwtArray[2].Length % 4 == 0 ? jwtArray[2] : jwtArray[2] + "====".Substring(jwtArray[2].Length % 4)).Replace("_", "/").Replace("-", "+");
        var jwtSignatureBytes = Convert.FromBase64String(jwtSignatureFixed);

        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.ImportParameters(
            new RSAParameters()
            {
                Modulus = publicKeyBytes,
                Exponent = Convert.FromBase64String(exponent)
            }
        );

        SHA256 sha256 = SHA256.Create();
        byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(jwtArray[0] + '.' + jwtArray[1]));

        RSAPKCS1SignatureDeformatter rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
        rsaDeformatter.SetHashAlgorithm("SHA256");
        if (!rsaDeformatter.VerifySignature(hash, jwtSignatureBytes))
        {
            errorMessage = "Error verifying JWT token signature: hash did not match expected value.";
            return false;
        }
    }
    catch (Exception ex)
    {
        errorMessage = "Error verifying JWT token signature: " + ex.Message;
        return false;
        //throw ex;
    }

    errorMessage = string.Empty;
    return true;
}

NOTE: Verifying the signature of an OpenID Connect JWT (Javascript Web Token) is only one necessary step of the JWT verification process. Make sure to set a NONCE value which your system can use to prevent Replay attacks. Make sure to validate each parameter of the JWT package for completeness and accuracy.

Share:
76,062
Dmitry Nikolaev
Author by

Dmitry Nikolaev

Know something about SmartBear products. :)

Updated on July 05, 2022

Comments

  • Dmitry Nikolaev
    Dmitry Nikolaev over 1 year

    Ok, I understand that the question I am asking may be pretty obvious, but unfortunately I lack the knowledge on this subject and this task seems to be quite tricky for me.

    I have an id token (JWT) returned by OpenID Connect Provider. Here it is:

    eyJraWQiOiIxZTlnZGs3IiwiYWxnIjoiUlMyNTYifQ.ewogImlzcyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZfV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5NzAsCiAiY19oYXNoIjogIkxEa3RLZG9RYWszUGswY25YeENsdEEiCn0.XW6uhdrkBgcGx6zVIrCiROpWURs-4goO1sKA4m9jhJIImiGg5muPUcNegx6sSv43c5DSn37sxCRrDZZm4ZPBKKgtYASMcE20SDgvYJdJS0cyuFw7Ijp_7WnIjcrl6B5cmoM6ylCvsLMwkoQAxVublMwH10oAxjzD6NEFsu9nipkszWhsPePf_rM4eMpkmCbTzume-fzZIi5VjdWGGEmzTg32h3jiex-r5WTHbj-u5HL7u_KP3rmbdYNzlzd1xWRYTUs4E8nOTgzAUwvwXkIQhOh5TPcSMBYy6X3E7-_gr9Ue6n4ND7hTFhtjYs3cjNKIA08qm5cpVYFMFMG6PkhzLQ

    Its header and payload are decoded as this:

    {
     "kid":"1e9gdk7",
     "alg":"RS256"
    }.
    {
     "iss": "http://server.example.com",
     "sub": "248289761001",
     "aud": "s6BhdRkqt3",
     "nonce": "n-0S6_WzA2Mj",
     "exp": 1311281970,
     "iat": 1311280970,
     "c_hash": "LDktKdoQak3Pk0cnXxCltA"
    }
    

    From the OIDC provider's discovery, I've got the public key (JWK):

    {
     "kty":"RSA",
     "kid":"1e9gdk7",
     "n":"w7Zdfmece8iaB0kiTY8pCtiBtzbptJmP28nSWwtdjRu0f2GFpajvWE4VhfJAjEsOcwYzay7XGN0b-X84BfC8hmCTOj2b2eHT7NsZegFPKRUQzJ9wW8ipn_aDJWMGDuB1XyqT1E7DYqjUCEOD1b4FLpy_xPn6oV_TYOfQ9fZdbE5HGxJUzekuGcOKqOQ8M7wfYHhHHLxGpQVgL0apWuP2gDDOdTtpuld4D2LK1MZK99s9gaSjRHE8JDb1Z4IGhEcEyzkxswVdPndUWzfvWBBWXWxtSUvQGBRkuy1BHOa4sP6FKjWEeeF7gm7UMs2Nm2QUgNZw6xvEDGaLk4KASdIxRQ",
     "e":"AQAB"
    }
    

    So, the question is how exactly in C# can I verify this JWT using the public key for the RS256 algorithm I've got? It would be awesome if there is a good tutorial describing this procedure explicitly. However, an example of how to do this using System.IdentityModel.Tokens.Jwt will also work fine.

    UPDATE: I understand, that I need to do something like the code below, but I have no idea where to get 'key' for calculating SHA256 hash.

      string tokenStr = "eyJraWQiOiIxZTlnZGs3IiwiYWxnIjoiUlMyNTYifQ.ewogImlzcyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZfV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5NzAsCiAiY19oYXNoIjogIkxEa3RLZG9RYWszUGswY25YeENsdEEiCn0.XW6uhdrkBgcGx6zVIrCiROpWURs-4goO1sKA4m9jhJIImiGg5muPUcNegx6sSv43c5DSn37sxCRrDZZm4ZPBKKgtYASMcE20SDgvYJdJS0cyuFw7Ijp_7WnIjcrl6B5cmoM6ylCvsLMwkoQAxVublMwH10oAxjzD6NEFsu9nipkszWhsPePf_rM4eMpkmCbTzume-fzZIi5VjdWGGEmzTg32h3jiex-r5WTHbj-u5HL7u_KP3rmbdYNzlzd1xWRYTUs4E8nOTgzAUwvwXkIQhOh5TPcSMBYy6X3E7-_gr9Ue6n4ND7hTFhtjYs3cjNKIA08qm5cpVYFMFMG6PkhzLQ";
      string[] tokenParts = tokenStr.Split('.');
    
      RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
      rsa.ImportParameters(
        new RSAParameters() {
          Modulus = FromBase64Url("w7Zdfmece8iaB0kiTY8pCtiBtzbptJmP28nSWwtdjRu0f2GFpajvWE4VhfJAjEsOcwYzay7XGN0b-X84BfC8hmCTOj2b2eHT7NsZegFPKRUQzJ9wW8ipn_aDJWMGDuB1XyqT1E7DYqjUCEOD1b4FLpy_xPn6oV_TYOfQ9fZdbE5HGxJUzekuGcOKqOQ8M7wfYHhHHLxGpQVgL0apWuP2gDDOdTtpuld4D2LK1MZK99s9gaSjRHE8JDb1Z4IGhEcEyzkxswVdPndUWzfvWBBWXWxtSUvQGBRkuy1BHOa4sP6FKjWEeeF7gm7UMs2Nm2QUgNZw6xvEDGaLk4KASdIxRQ"),
          Exponent = FromBase64Url("AQAB")
        });
    
      HMACSHA256 sha = new HMACSHA256(key);
      byte[] hash = sha.ComputeHash(Encoding.UTF8.GetBytes(tokenParts[0] + '.' + tokenParts[1]));
      byte[] signature = rsa.Encrypt(hash, false);
      string strSignature = Base64UrlEncode(signature);
      if (String.Compare(strSignature, tokenParts[2], false) == 0)
        return true;
    
    • jwilleke
      jwilleke over 8 years
      Which role are you fulfilling? (Client, Resource Server?)
    • Dmitry Nikolaev
      Dmitry Nikolaev over 8 years
      It's a client application. It should work with a custom OIDC provider (do not have control over it) that uses the RS256 signing algorithm. Everything works fine by the moment and the signature verification is the latest obstacle I am facing.
    • jwilleke
      jwilleke over 8 years
    • Dmitry Nikolaev
      Dmitry Nikolaev over 8 years
      Absolutely! Thank you jwilleke!
  • explunit
    explunit over 8 years
    Just curious why you are choosing to use the low-level constructs here rather than System.IdentityModel.Tokens.Jwt?
  • Dmitry Nikolaev
    Dmitry Nikolaev over 8 years
    First of all, documentation for 'System.IdentityModel.Tokens.Jwt' is awful and out-of-date. The current version of this package has other APIs that are different from those documented in MSDN. I tried using it and it worked for me in general, but I was unable to find a way to perform this simple task of token signature verification.
  • Dmitry Nikolaev
    Dmitry Nikolaev over 8 years
    And the second reason is that I will be working with custom OIDC providers and it is possible that I will be unable to get the list of public keys for one of them. In this situation, I will need to skip signature verification that is, I think, impossible with 'System.IdentityModel.Tokens.Jwt'.
  • Rob Van Pamel
    Rob Van Pamel over 7 years
    When using .net core in a Unix environment, you can not use the RSACryptoServiceProvider. There is an alternative way in the system.security.cryptography.algorithms. You can use rsa straightaway over there.
  • Reath
    Reath over 5 years
    I've been searching for this solution for 2 days. Thank you very much @NvMat
  • t2t
    t2t about 5 years
    Great answer @NvMat. I used your approach for the AddJwtBearer() auth flow in a net core web api.
  • Frédéric
    Frédéric almost 5 years
    This way of doing things, stripping/decoding manually to a byte array before using BouncyCastle, was failing for me (exception in BouncyCastle). Instead, using BouncyCastle PemReader directly on the key text with ----- delimiters was easier for me and working. I have found this other way in this question.
  • Prateek Kumar Dalbehera
    Prateek Kumar Dalbehera about 4 years
    Thanks for the detailed solution. "Very important is to not use the RSACryptoServiceProvider in an using statement." -- For other readers, if used inside using statement, then .Net Core will complain that "Invalid Token Signature".
  • Kamran Shahid
    Kamran Shahid about 4 years
    Any possible solution within .net core 3.1 with TokenValidationParameters without using bouncy castle.
  • tsiro
    tsiro almost 4 years
    what about JWT token generation with RSA signing algorith using private key...is RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048); new RsaSecurityKey(rsa.ExportParameters(true));...code sufficient?
  • andleer
    andleer over 3 years
    Use WebEncoders.Base64UrlDecode instead of rolling your own FromBase64Url method.
  • Nicholas Petersen
    Nicholas Petersen over 3 years
    Is Modulus input string the public key? I got this to work, great job and thank you, using your exact inputs here. But trying it out with an example here when select RS256, not succeeding to get something working: jwt.io/#debugger-io Would be nice to know what to set on these RSAParameters to get a live example working, but thanks mate!
  • Mister Q
    Mister Q over 3 years
    Hi, your condition ` if (jwtArray.Length != 3 || jwtArray.Length != 5)` is wrong, my token is 3 length long but I hit the error! Cheers for your answer, help me a lot!
  • Jason Williams
    Jason Williams over 3 years
    Thanks, Mister Q! I checked against my code base and found I had different logic. The correct logic is 'if (jwtArray.Length != 3 && jwtArray.Length != 5)'. I corrected this in the code, above.
  • Glen Carpenter
    Glen Carpenter over 2 years
    @NicholasPetersen I know this is a bit late, but the modulus and exponent are derived from the Base64URL encoded public key. Usually they are on the JWK as the "n" and "e" keys. If you do not have a JWK, you will need to derive these values somehow, as the public key string itself will not work.
  • Mikhail Kh
    Mikhail Kh over 2 years
    Thanks! But I got issue with this approach - first time validation success, but second time it catch exception. When I remove using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) and keep just: RSACryptoServiceProvider rsa = new RSACryptoServiceProvider() It start works fine. When I add rsa.Dispose() in the end, I couught same issue
  • HitLikeAHammer
    HitLikeAHammer almost 2 years
    When I try this I get "cannot convert from 'System.Security.Cryptography.RSA' to 'System.Security.Cryptography.X509Certificates.X509Certifica‌​te2' on this: new RS256Algorithm(rsaKey)