How to fix Signature validation failed when trying to validate an access token of Microsoft Entra ID

Bernardo Garza García 5 Reputation points
2024-06-07T20:44:34.87+00:00

Hi,

I'm trying to validate my access token signature from Microsoft Entra ID, as you can see in the below image, the "kid" attribute is different from the keys retrieved in the second image below that were retrieved from [domain+tenant]/.well-known/openid-configuration

This is causing the next error: The token's kid is: 'f0GUng0wL6zx4dx1Iuu1ForRHEA', but did not match any keys in TokenValidationParameters 

Could you try to help me to understand if I am doing something wrong ? This only happens with Microsoft Entra ID, it works when using Azure AD B2C

Image preview

Image preview

StackTrace:

HResult=0x80131500

  Message=IDX10503: Signature validation failed. The token's kid is: 'f0GUng0wL6zx4dx1Iuu1ForRHEA', but did not match any keys in TokenValidationParameters or Configuration. Keys tried: 'Microsoft.IdentityModel.Tokens.X509SecurityKey, KeyId: 'q-23falevZhhD3hm9CQbkP5MQyU', InternalId: 'q-23falevZhhD3hm9CQbkP5MQyU'. , KeyId: q-23falevZhhD3hm9CQbkP5MQyU

Microsoft.IdentityModel.Tokens.RsaSecurityKey, KeyId: 'q-23falevZhhD3hm9CQbkP5MQyU', InternalId: 'S_S12adpbe27-_qkluYZHCSMRJ6EcrW5Ho4cyLGEjG8'. , KeyId: q-23falevZhhD3hm9CQbkP5MQyU

Microsoft.IdentityModel.Tokens.X509SecurityKey, KeyId: 'V1Y09OFMBXAZUFfJ-vWjlrH-ZSc', InternalId: 'V1Y09OFMBXAZUFfJ-vWjlrH-ZSc'. , KeyId: V1Y09OFMBXAZUFfJ-vWjlrH-ZSc

Microsoft.IdentityModel.Tokens.RsaSecurityKey, KeyId: 'V1Y09OFMBXAZUFfJ-vWjlrH-ZSc', InternalId: '21yYN7-15_HEG6Myr8mw1D07vAMCN503j4n1GnsWWJQ'. , KeyId: V1Y09OFMBXAZUFfJ-vWjlrH-ZSc

Microsoft.IdentityModel.Tokens.X509SecurityKey, KeyId: 'L1KfKFI_jnXbwWc22xZxw1sUHH0', InternalId: 'L1KfKFI_jnXbwWc22xZxw1sUHH0'. , KeyId: L1KfKFI_jnXbwWc22xZxw1sUHH0

Microsoft.IdentityModel.Tokens.RsaSecurityKey, KeyId: 'L1KfKFI_jnXbwWc22xZxw1sUHH0', InternalId: 'RlwaR9qe84mGeeFWVsLX3zezPkY88aZiSkDuuqUxftM'. , KeyId: L1KfKFI_jnXbwWc22xZxw1sUHH0

Microsoft.IdentityModel.Tokens.X509SecurityKey, KeyId: 'UxyGE-ffaoAkooUxUFn0ar7fvDM', InternalId: 'UxyGE-ffaoAkooUxUFn0ar7fvDM'. , KeyId: UxyGE-ffaoAkooUxUFn0ar7fvDM

Microsoft.IdentityModel.Tokens.RsaSecurityKey, KeyId: 'UxyGE-ffaoAkooUxUFn0ar7fvDM', InternalId: 'IC5xpkooVq3LolG30n_19Ollz-mDTXlIuq4MdlmjwFE'. , KeyId: UxyGE-ffaoAkooUxUFn0ar7fvDM

Microsoft.IdentityModel.Tokens.X509SecurityKey, KeyId: 'EHu9neGZBCDyv2IYq8U5JiRMFng', InternalId: 'EHu9neGZBCDyv2IYq8U5JiRMFng'. , KeyId: EHu9neGZBCDyv2IYq8U5JiRMFng

Microsoft.IdentityModel.Tokens.RsaSecurityKey, KeyId: 'EHu9neGZBCDyv2IYq8U5JiRMFng', InternalId: '4xRadtB97YyM0GXtJGF1MHO11LmoVHRCXd4Gp3tNb6Y'. , KeyId: EHu9neGZBCDyv2IYq8U5JiRMFng

'. Number of keys in TokenValidationParameters: '10'. 

.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,921 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
11,012 questions
Microsoft Entra ID
Microsoft Entra ID
A Microsoft Entra identity service that provides identity management and access control capabilities. Replaces Azure Active Directory.
22,116 questions
{count} vote

2 answers

Sort by: Most helpful
  1. James Hamil 25,396 Reputation points Microsoft Employee
    2024-06-10T20:30:33.37+00:00

    Hi @Bernardo Garza García , can you please try the following for me?

    1. Check if the authority that issued the token is the same as the one you are trying to validate against. You can do this by comparing the "iss" claim in the token with the authority's URL.
    2. Check if the signing keys have been updated since the token was issued. You can retrieve the latest signing keys from the OpenID configuration endpoint and compare them with the "kid" attribute in the token. If they are different, you can update your validation logic to use the latest signing keys.
    3. If you are still having issues, you can try enabling the "RefreshOnIssuerKeyNotFound" option in your validation logic. This will force the validation logic to retrieve the latest signing keys from the OpenID configuration endpoint if the "kid" attribute in the token does not match any of the cached keys.

    Please let me know your results and I can help you further.

    Best,

    James

    0 comments No comments

  2. Linus Lim Duann Shiun 0 Reputation points
    2024-09-09T08:29:08.12+00:00

    Hi, I have the same exact problems here. I am trying to authenticate the organization users of my .NET Framework 4.8 app using OpenID Connect, and somehow the KID of my token doesn't match with any of those found in the discovery URL.

    These are my codes. Appreciate if anyone could shed some light on the issue here.

    public class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                // Enable PII logging for debugging purposes
                IdentityModelEventSource.ShowPII = true;
    
                ConfigureAuth(app);
            }
    
            public void ConfigureAuth(IAppBuilder app)
            {
    
                app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
                app.UseCookieAuthentication(new CookieAuthenticationOptions());
    
                app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
                {                
                    ClientId = ConfigurationManager.AppSettings["ida:ClientId"],
                    Authority = $"https://login.microsoftonline.com/{ConfigurationManager.AppSettings["ida:TenantId"]}" + "/v2.0",
                    RedirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"],
                    PostLogoutRedirectUri = ConfigurationManager.AppSettings["ida:PostLogoutRedirectUri"],
                    ResponseType = "id_token",
                    TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = true,
                        ValidateAudience = true,
                        ValidateLifetime = true,                                        
                        ValidAudience = ConfigurationManager.AppSettings["ida:ClientId"],
                        ValidIssuer = $"https://login.microsoftonline.com/{ConfigurationManager.AppSettings["ida:TenantId"]}" + "/v2.0",
    
                        IssuerSigningKeyResolver = (token, securityToken, kid, parameters) =>
                        {
                            try
                            {
                                var configurationManager = new Microsoft.IdentityModel.Protocols.ConfigurationManager<Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfiguration>(
                                $"https://login.microsoftonline.com/{ConfigurationManager.AppSettings["ida:TenantId"]}/v2.0/.well-known/openid-configuration",
                                new Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever());
    
                                // Force refresh
                                configurationManager.RequestRefresh();
    
                                var discoveryDocument = configurationManager.GetConfigurationAsync().Result;                                                      
    
                                // Log all signing keys
                                foreach (var key in discoveryDocument.SigningKeys)
                                {
                                    System.Diagnostics.Debug.WriteLine($"KeyId: {key.KeyId}, Key: {key}");
                                }
    
                                // Log the token and kid for debugging
                                System.Diagnostics.Debug.WriteLine("Token: " + token);
                                System.Diagnostics.Debug.WriteLine("Kid: " + kid);
    
                                // Find and return the matching key
                                var matchingKeys = discoveryDocument.SigningKeys.Where(k => k.KeyId == kid).ToList();
                                if (!matchingKeys.Any())
                                {
                                    System.Diagnostics.Debug.WriteLine($"No matching key found for kid: {kid}");
                                    throw new SecurityTokenInvalidSignatureException("No matching key found.");
                                }
    
                                return matchingKeys;
                            }
                            catch (Exception ex)
                            {
                                System.Diagnostics.Debug.WriteLine("Error retrieving signing keys: " + ex.Message);
                                throw;
                            }
                        },                   
                    },                
                    Notifications = new OpenIdConnectAuthenticationNotifications
                    {
                        AuthenticationFailed = context =>
                        {
                            context.HandleResponse();
                            context.Response.Redirect("/Error?message=" + context.Exception.Message);
                            return Task.FromResult(0);
                        },
                        SecurityTokenValidated = context =>
                        {
                            /*
                            string name = context.AuthenticationTicket.Identity.FindFirst("preferred_username").Value;
                            context.AuthenticationTicket.Identity.AddClaim(new Claim(ClaimTypes.Name, name, string.Empty));
                            return System.Threading.Tasks.Task.FromResult(0);
                            */
    
                            return Task.FromResult(0);
                        },        
                    },
                    SignInAsAuthenticationType = "Cookies",  // Ensure this matches the Cookie AuthenticationType (IMPORTANT: THIS PARAM MUST BE IN THE LAST POSITION)
                });
            }
        }
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.