Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Azure AD - Why can't I validate JWT token issued by Azure AD for my Web API? Getting "IDX10516: Signature validation failed" error

I have a Web API that is protected by Azure AD. I am able to get access token for the Web API from Azure AD and use it successfully.

What I want to do is validate the token before performing any operation using that token so that I can give meaningful error messages to the user in case there's something wrong with the token. For example, some of the things I would like to tell user are:

  1. Whether or not the token has expired?
  2. Whether or not the token is acquired for correct audience?
  3. Whether or not the token issuer is valid?

However I am not able to do so because regardless of whether the token is valid or invalid, I am constantly getting the following error message:

IDX10516: Signature validation failed. Unable to match key: 
kid: 'System.String'.
Exceptions caught:
 'System.Text.StringBuilder'. 
token: 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken'. Valid Lifetime: 'System.Boolean'. Valid Issuer: 'System.Boolean'

I am successfully able to parse the token at https://jwt.io.

Under the "Header" section there, I see the following:

{
  "typ": "JWT",
  "alg": "RS256",
  "x5t": "qDm8HXaLQBeSIvYXzMt8PQ_ADFt",//obfuscated
  "kid": "qDm8HXaLQBeSIvYXzMt8PQ_ADFt"//obfuscated
}

Also, I get Signature Verified message as well as shown in the screenshot below.

enter image description here

Here's the code I wrote:

string authorizationToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Im5PbzNaRHJPRFhFSzFqS1doWHNsSFJfS1hFZyIsImt...";
try
{
    JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();

    TokenValidationParameters tokenValidationParameters = new TokenValidationParameters()
    {
        ValidateLifetime = true,
    };
    var claimsPrincipal = tokenHandler.ValidateToken(authorizationToken, tokenValidationParameters, out _);//Exception comes on this line.
}
catch (SecurityTokenExpiredException exception)
{
    //Do something with the token expired exception
}
catch (SecurityTokenInvalidAudienceException exception)
{
    //Do something with invalid audience exception
}
catch (Exception exception) //Code always lands in this exception block
{
    //Token is invalid because of some other reason
}

As I said above, my code is always landing in the last exception block regardless of whether the token is valid or not.

Can anyone please tell me what I am doing wrong here? What is needed to successfully validate the token?

Any insights into this will be highly appreciated.

like image 837
Gaurav Mantri Avatar asked Oct 25 '25 18:10

Gaurav Mantri


1 Answers

To validate the token, you need to specify the keys used by the identity provider (Azure AD) to sign the token:

using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var token = "<my token>";
            var tenantid = "<my azure ad  tenant id>";

            // => use to retrieve the keys used by AAD to sign the token
            var openidConfigManaged = new ConfigurationManager<OpenIdConnectConfiguration>(
                $"https://login.microsoftonline.com/{tenantid}/v2.0/.well-known/openid-configuration",
                new OpenIdConnectConfigurationRetriever(),
                new HttpDocumentRetriever());
            var config = await openidConfigManaged.GetConfigurationAsync();

            var parameteres = new TokenValidationParameters()
            {
                RequireAudience = true,
                RequireExpirationTime = true,
                ValidateAudience = true,
                ValidateIssuer = true,
                ValidateLifetime = true,
                // The Audience should be the requested resource => client_id and or resource identifier.
                // Refer to the "aud" claim in the token
                ValidAudiences = new[] { "<my client id or resource identitifer>" },
                // The issuer is the identity provider
                // Refer to the "iss" claim in the token
                ValidIssuers = new[] { $"https://sts.windows.net/{tenantid}/" }, 
                IssuerSigningKeys = config.SigningKeys
            };

            var tokenHandler = new JwtSecurityTokenHandler();
            var claimPrincipal = tokenHandler.ValidateToken(token, parameteres, out _);
        }
    }
}
like image 158
Thomas Avatar answered Oct 28 '25 08:10

Thomas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!