Reputation: 2523
I am using this great method, found in this article https://codingstill.com/2016/01/verify-jwt-token-signed-with-rs256-using-the-public-key/#comment-3232, to validate my Azure idToken, which is signed with RS256.
I noticed that Azure AD changes the public key in a period of time. By reading this article, https://nicksnettravels.builttoroam.com/post-2017-01-24-verifying-azure-active-directory-jwt-tokens-aspx. Therefore, I used HttpClient (c#) to obtain the public key from the URL below, every time when I need to validate the token.
https://login.microsoftonline.com/{TenantId}/discovery/v2.0/keys?appid={AppId}
I did get the result of the public key, which is a string array in x5c key. Below is my code:
public static string GetPublicKeyAsync(string kid)
{
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<ADPublic> allPublicKeys = JsonConvert.DeserializeObject<List<ADPublic>>(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 the validation method. I always get an error at the line (PublicKeyFactory.CreateKey(keyBytes) method ):
Please refer to the verify method I mentioned in the beginning of this question for the code below:
// 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
I think I am almost there, but missing the last part, could you please help? Thank you very much!
Upvotes: 1
Views: 1578
Reputation: 7473
I got the same error when using certificate.PublicKey.EncodedKeyValue.RawData
to get the public key. I referred to this issue and finally succeeded.
The code shows getting AsymmetricKeyParameter
from x5c string. Decode(...)
function is referred to in the article.
string token = "<the token that you want to verify>";
string certificateString = "<the first x5c of the first key from https://login.microsoftonline.com/{TenantId}/discovery/v2.0/keys?appid={AppId}>";
byte[] buffer = Convert.FromBase64String(certificateString);
X509CertificateParser parser = new X509CertificateParser();
var _certificate = parser.ReadCertificate(buffer);
AsymmetricKeyParameter publicKey = _certificate.GetPublicKey();
string result = Decode(token, publicKey);
Console.WriteLine("result: " + result);
Upvotes: 0