• Skip to main content
  • Skip to primary sidebar
  • Skip to secondary sidebar
  • Skip to footer

Coding Still

  • Home
  • About

Verify JWT token signed with RS256 using the public key

January 6, 2016 By _tasos 21 Comments

In this article we will see how we can verify a JWT token that has been signed with the RS256 algorithm. While there are more than a few libraries for .NET that provide functionality to decode and verify JWT tokens, none of them support the specific algorithm.

In short, a JWT token consists of three parts seperated by a .; the first part is the algorithm used to sign the token, the second part is the actual data and the third part is the signature we need to match so that the token can be verified.

If you are not very familiar with JWT tokens, here you can read a very good article about them and their anatomy.

The code provided in this article is for tokens that have the following header:

{
  "alg": "RS256"
}

Here is the Decode(...) function that can verify a RS256 signed JWT token. It makes use of the BouncyCastle library. It is available as a NuGet package with version 1.7.0 but on their website version 1.8.1 is available. The code is tested with both versions and works fine.

using System;
using System.Security.Cryptography;
using System.Text;
using Newtonsoft.Json.Linq;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
 
public static string Decode(string token, string key, bool verify = true)
{
    string[] parts = token.Split('.');
    string header = parts[0];
    string payload = parts[1];
    byte[] crypto = Base64UrlDecode(parts[2]);
 
    string headerJson = Encoding.UTF8.GetString(Base64UrlDecode(header));
    JObject headerData = JObject.Parse(headerJson);
 
    string payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(payload));
    JObject payloadData = JObject.Parse(payloadJson);
 
    if (verify)
    {
        var keyBytes = Convert.FromBase64String(key); // your key here
 
        AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes);
        RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
        RSAParameters rsaParameters = new RSAParameters();
        rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
        rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.ImportParameters(rsaParameters);
 
        SHA256 sha256 = SHA256.Create();
        byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(parts[0] + '.' + parts[1]));
 
        RSAPKCS1SignatureDeformatter rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
        rsaDeformatter.SetHashAlgorithm("SHA256");
        if (!rsaDeformatter.VerifySignature(hash, FromBase64Url(parts[2])))
            throw new ApplicationException(string.Format("Invalid signature"));
    }
 
    return payloadData.ToString();
}

Here are some helper functions used in the above snippet.

// from JWT spec
private static byte[] Base64UrlDecode(string input)
{
    var output = input;
    output = output.Replace('-', '+'); // 62nd char of encoding
    output = output.Replace('_', '/'); // 63rd char of encoding
    switch (output.Length % 4) // Pad with trailing '='s
    {
        case 0: break; // No pad chars in this case
        case 1: output += "==="; break; // Three pad chars
        case 2: output += "=="; break; // Two pad chars
        case 3: output += "="; break; // One pad char
        default: throw new System.Exception("Illegal base64url string!");
    }
    var converted = Convert.FromBase64String(output); // Standard base64 decoder
    return converted;
}

The above is a combination of code snippets found in the following links

  • http://stackoverflow.com/questions/34403823/verifying-jwt-signed-with-the-rs256-algorithm-using-public-key-in-c-sharp. This article contains part of the solution since it does not provide how to get the Modulus and the Exponent from the public key
  • http://stackoverflow.com/questions/29455404/net-equivalent-of-java-keyfactory-getinstance-rsa-rsa-ecb-pkcs1padding. This article shows how we can get the Modulus and the Exponent from the public key.
  • http://stackoverflow.com/questions/10055158/is-there-a-json-web-token-jwt-example-in-c. Although the code there is tweaked to support RS256 it actually supports the HS256 instead. I got the helper functions from this article though; the code there is pretty much based on John Sheehans JWT library.

Update: I have also written the Sign(...) function that complements this one, click here to see it.

Update 2: You can check this post here, where I have created a C# library that manages Jwt tokens.

Update 3: If you are having trouble making your keys work, have a look in my Check your RSA private and public keys post and make sure to check the Additional Resources section as well

Filed Under: .NET Development Tagged With: Bouncy Castle, JWT

Reader Interactions

Comments

  1. Adam says

    March 22, 2016 at 16:51

    Thank you! This was the best example I found regarding decoding a JWT token using a RS256 public key.

    In case anyone else runs into this, the key variable should be the public key all on one line and removing the “—–BEGIN PUBLIC KEY—–” and “—–END PUBLIC KEY—–“. Otherwise, you will get an exception on this line “var keyBytes = Convert.FromBase64String(key);”.

    Thanks again,
    Adam

    Reply
  2. Sammy says

    June 9, 2016 at 20:49

    I’m using Google API from an app to access my own account at Google. Per their doc, I created a “service account” and downloaded the file that has PRIVATE key, client_email, auth uri, token uri etc. There is no public key.
    Using RS256, I created JWT based on the given private key.
    Now I need to validate that JWT. Your “Decode” function will not work for me since I do not have the public key. Is there a way to decode using the same private key or am I missing something?
    Thanks!

    Reply
    • _tasos says

      June 9, 2016 at 23:17

      Hey Sammy.

      Since you have the private key, it is easy to generate the public key and then use the function in the post.

      I haven’t tried it but there is this SO post that you might find helpful http://stackoverflow.com/questions/5244129/use-rsa-private-key-to-generate-public-key.

      Reply
  3. Wei says

    August 11, 2016 at 22:35

    Hey tasos,

    Thank you! I couldn’t find better examples out there regarding verifying a Jwt token using RSA256 public key. Many of other examples are simply showing how to do it using HS256 algorithm.

    I also tried to find examples of how to generate a signed Jwt token using RSA256 private keys and I don’t get any luck so far. I would appreciate if you could write an article or just a sample code showing how to generate a Jwt using the Bouncy Castle lib in C# with RSA256 private key?

    Thanks!

    Reply
  4. Raju says

    January 20, 2017 at 23:07

    Hello,

    I am looking for similar article to verify RS256 signature. Would you please share me the link if anyone has it?

    Thanks, in advance.

    Reply
    • _tasos says

      February 24, 2018 at 01:31

      Hello Raju, I have written a post with the Sign(…) function, you can have a look here.

      Reply
  5. Cristian says

    December 5, 2017 at 18:07

    Dude, you save my day!
    One billion thanks for that, great article and solution!!!

    Reply
  6. Rohan says

    November 19, 2018 at 13:16

    Hi Tasos,
    This article is great. I could accomplish the JWT signature verification with the BouncyCastle.
    But for this we need to have public key in(pem generated) I have a issuer key and i want to generate PEM key using C#.
    How do I do that?
    And also is BouncyCastle is openSource?
    –Rohan

    Reply
  7. Rushal Maksane says

    December 24, 2018 at 13:11

    Can you please provide Base64URlDecode function?

    Reply
  8. ozan says

    March 21, 2019 at 17:41

    Hi I have been trying to validate my JWT with the public key. I tried on JWT.io and it verified successfully. When I try on this code, I keep getting the exception “Bad sequence size: 3
    Parameter name: seq” when the code executes the following line:

    AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes)

    Any advice?

    Thank you!

    Reply
    • _tasos says

      March 25, 2019 at 16:44

      Hi Ozan,

      It could be the issue on how you read the file. After loading the .pem file, pass the input via this helper function.

      private static string RemoveHeaderFooterFromKey(string key)
      {
          string tmp = key;
          tmp = tmp.Replace("\n", "");
          tmp = tmp.Replace("-----BEGIN PRIVATE KEY-----", "");
          tmp = tmp.Replace("-----END PRIVATE KEY-----", "");
          tmp = tmp.Replace("-----BEGIN RSA PRIVATE KEY-----", "");
          tmp = tmp.Replace("-----END RSA PRIVATE KEY-----", "");
          tmp = tmp.Replace("-----BEGIN PUBLIC KEY-----", "");
          tmp = tmp.Replace("-----END PUBLIC KEY-----", "");
          return tmp;
      }
      string fullPpublicKey = File.ReadAllText(publicKeyPath);
      string publicKey = RemoveHeaderFooterFromKey(fullPpublicKey);

      Also, have a look in this GitHub repo, where there is the whole code with tests to use as examples.

      Reply
  9. Jr says

    June 3, 2019 at 06:56

    I am getting error for FromBase64Url() function. Getting error at FromBase64Url(parts[2])

    Reply
    • _tasos says

      June 3, 2019 at 23:02

      Hi there. An error there indicates that the signature doesn’t match. Consider posting a question in SO with your code so that I can have a look.

      Reply
  10. jr says

    June 4, 2019 at 16:39

    First of all Thank you _Tasos, your code is very helpful.

    I should rephrase, I am getting compile error @

    if (!rsaDeformatter.VerifySignature(hash, FromBase64Url(parts[2])))
    throw new ApplicationException(string.Format(“Invalid signature”));

    where FromBase64Url function is missing. I am looking for how to get byte from Base64Url string.

    Reply
  11. Jr says

    June 4, 2019 at 16:59

    I was able to find the FromBase64Url Function and was able to verify the signature as will. Thanks again for the nice post!

    Pasting the function,

    // https://stackoverflow.com/questions/34284810/decoding-base64urluint-encoded-value
    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);
    }
    Reply
  12. Bin says

    September 12, 2019 at 15:21

    Hi , Thanks for the post. I am getting error

    ‘Bad sequence size: 3
    Parameter name: seq’.

    I am using RemoveHeaderFooterFromKey menthod as you mentioned . But still I am getting same error. Can you please help me.?

    Reply
    • _tasos says

      September 14, 2019 at 19:40

      Hi Bin,

      It could be that there is a mixup with the key. Make sure that your key contains the lines the RemoveHeaderFooterFromKey tries to remove

      Reply
  13. George says

    September 8, 2020 at 22:59

    Hi _tasos,

    This is a GREAT example! I have been struggling getting my public key. Please help me.

    I am using Azure AD to authenticate users. I passed IdToken over to my server side for the validation.

    I noticed that Azure AD changes public key in a period of times. By reading this artical, https://nicksnettravels.builttoroam.com/post-2017-01-24-verifying-azure-active-directory-jwt-tokens-aspx/, I used HttpClient (c#) to abtain the public key from the url in Azure.

    https://login.microsoftonline.com/{TenantId}/discovery/v2.0/keys?appid={AppId}

    I did get the result, which is an string array in x5c key. Below is my code:

     using (var client = new HttpClient())
                {
                    HttpResponseMessage response = client.GetAsync("https://login.microsoftonline.com/{tenantId}/discovery/v2.0/keys?appid={appId}").Result;
     
                    if (response.IsSuccessStatusCode)
                    {
                        var responseContent = response.Content;
     
                        // by calling .Result you are synchronously reading the result
                        string responseBody = responseContent.ReadAsStringAsync().Result;
     
                        JObject json = JObject.Parse(responseBody);
                        string c = json["keys"].ToString();
     
                        List allPublicKeys = JsonConvert.DeserializeObject<List>(json["keys"].ToString());
     
                        foreach (ADPublic key in allPublicKeys)
                        {
                            if (key.kid == kid)
                            {
                                string certificateString = key.x5c[0];
                                var certificate = new X509Certificate2(Convert.FromBase64String(certificateString));
     
                                string pkey = Convert.ToBase64String(certificate.PublicKey.EncodedKeyValue.RawData);
     
                              //  var x509SecurityKey = new X509SecurityKey(certificate)
                               // {
                                  //  KeyId = key.kid
                               // };
                                return pkey;
                            }
                        }
     
                    }
                    return null;
                }

    When I pass my public key over to your method. I always get an error at :

    // call my get public key function..
     string key = GetPublicKeyAsync(headerData["kid"].ToString());
     
    var keyBytes = Convert.FromBase64String(key); // your key here
     
            AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes);
     
    Unknown object in GetInstance: Org.BouncyCastle.Asn1.DerInteger Parameter name: obj
    Reply
    • _tasos says

      September 9, 2020 at 07:20

      Hi George,

      Thank you for your interest in my article. I would suggest to try the most recent version of the library from my Github repo.

      Also, check this post, where I have a command that can check the public key. You can use it to check if the key you are trying is indeed RS256.

      Reply
  14. Kannan says

    September 25, 2020 at 19:00

    Its throwing error in AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes), if we pass CERTIFICATE String

    Reply
    • _tasos says

      October 3, 2020 at 09:48

      Hi Kannan,

      Thank you for your comment. I would suggest to try the most recent version of the library from my Github repo.

      Also, check the previous comments, you might find them helpful.

      Reply

Leave a Reply to Sammy Cancel reply

Your email address will not be published. Required fields are marked *

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

Primary Sidebar

Categories

  • .NET Development
  • ASP.NET
  • Databases
  • Fun
  • IIS
  • JavaScript
  • Web Development

Tags

.NET Core Android ANTLR ASP.NET Ajax ASP.NET Core ASP.NET MVC ASP.NET Web Forms AWS Bouncy Castle Chartjs cli Client info detection Comic Continuous integration CSS Data backup Date handling Firebase Firefox addons Github HigLabo HTML5 Image manipulation jQuery JWT MySQL Nodejs Nuget OAuth Objectionjs OOP openssl Oracle ORM PHP Regular expressions SEO Social media SQL SQL Server UI/UX Url rewriting Videos Visual Studio Web design

Meta

  • Log in
  • Entries feed
  • Comments feed
  • WordPress.org

Secondary Sidebar

Archives

  • July 2020
  • March 2020
  • August 2019
  • December 2018
  • November 2018
  • February 2018
  • August 2016
  • June 2016
  • May 2016
  • February 2016
  • January 2016
  • August 2015
  • July 2015
  • October 2014
  • July 2014
  • November 2013
  • April 2013
  • February 2013
  • January 2013
  • December 2012
  • November 2012
  • August 2012
  • May 2012
  • February 2012
  • December 2011
  • October 2011
  • September 2011
  • August 2011
  • July 2011
  • May 2011
  • April 2011
  • March 2011
  • February 2011
  • January 2011
  • December 2010
  • November 2010
  • October 2010
  • September 2010
  • August 2010
  • July 2010

Footer

Recent Posts

  • Anatomy of an Objection.js model
  • Check your RSA private and public keys
  • Round functions on the Nth digit
  • Send FCM Notifications in C#
  • Jwt Manager
  • Things around the web #5
  • Query JSON data as relational in MySQL
  • Create and sign JWT token with RS256 using the private key
  • Drop all database objects in Oracle
  • Create and deploy a Nuget package

Latest tweets

  • Geekiness Intensifies.. NASA used Three.js to render a real-time simulation of this week's NASA rover landing on M… https://t.co/orgkXnYj9O February 19, 2021 18:12
  • Things I Wished More Developers Knew About Databases https://t.co/h4gfq6NJgo #softwaredevelopment #databases May 3, 2020 12:52
  • How a Few Lines of Code Broke Lots of Packages https://t.co/p7ZSiLY5ca #javascript May 3, 2020 12:48
  • Can someone steal my IP address and use it as their own? https://t.co/HoQ7Z3BG69 January 24, 2020 13:27
  • Organizational complexity is the best predictor of bugs in a software module https://t.co/aUYn9hD4oa #softwaredevelopment January 13, 2020 08:24
  • http://twitter.com/codingstill

Misc Links

  • George Liatsos Blog
  • Plethora Themes
  • C# / VB Converter
  • Higlabo: .NET library for mail, DropBox, Twitter & more

Connect with me

  • GitHub
  • LinkedIn
  • RSS
  • Twitter
  • Stack Overflow

Copyright © 2021 · eleven40 Pro on Genesis Framework · WordPress · Log in