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
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
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!
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.
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!
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.
Hello Raju, I have written a post with the Sign(…) function, you can have a look here.
Dude, you save my day!
One billion thanks for that, great article and solution!!!
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
Can you please provide Base64URlDecode function?
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!
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.
Also, have a look in this GitHub repo, where there is the whole code with tests to use as examples.
I am getting error for FromBase64Url() function. Getting error at FromBase64Url(parts[2])
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.
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.
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,
Hi , Thanks for the post. I am getting error
I am using RemoveHeaderFooterFromKey menthod as you mentioned . But still I am getting same error. Can you please help me.?
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 removeHi _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:
When I pass my public key over to your method. I always get an error at :
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.
Its throwing error in AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes), if we pass CERTIFICATE String
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.
I am getting this error at this line
RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
Unhandled exception. System.InvalidCastException: Unable to cast object of type ‘Org.BouncyCastle.Crypto.Parameters.ECPublicKeyParameters’ to type ‘Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters’.
at JwtDecode.Program.VerifyToken(String token, String key) in C:\Users\jagad\OneDrive\Desktop\Jwt Decode\Jwt Decode\Program.cs:line 69
at JwtDecode.Program.Main(String[] args) in C:\Users\jagad\OneDrive\Desktop\Jwt Decode\Jwt Decode\Program.cs:line 167
Hi Aleti,
Check the library, I have a repo with it in GitHub. It has the latest version and a few bugs sorted out.
Alternatively, you can post your question on StackOverflow with a code snippet. Then, post the link here so I can follow up.
Hello,
Thanks for this wonderful code stuff. I have been testing this with my JWT token validation with keycloak. I am getting false from below code all the time. Do you know any reason for this signature validation failure?
var result = rsaDeformatter.VerifySignature(hash, FromBase64Url(parts[2]));
Hi Sumal,
This line performs the verification of the JWT token. If it throws an exception, I would confirm that the public key I use is the correct one. Check the bottom of the post, it has some links to other articles that may be useful, specifically this one: Check your RSA private and public keys.
Also, consider using the latest version of the code from my repository in GitHub.