|
| 1 | +--- |
| 2 | +title: Troubleshoot Access Token Signature Validation Errors |
| 3 | +description: Helps you troubleshoot access token signature validation errors and provides solutions in some scenarios. |
| 4 | +ms.date: 08/11/2025 |
| 5 | +ms.reviewer: willfid |
| 6 | +ms.service: entra-id |
| 7 | +ms.custom: sap:Developing or Registering apps with Microsoft identity platform |
| 8 | +--- |
| 9 | +# Troubleshoot access token signature validation errors |
| 10 | + |
| 11 | +When a resource provider validates an access token's signature, signature validation errors occur. These errors might result from the signing key being unavailable or failing to validate the signature. This article helps you troubleshoot such errors and provides solutions in some scenarios. |
| 12 | + |
| 13 | +## Step 1: Decode the access token |
| 14 | + |
| 15 | +1. Get the access token being sent to the resource provider. |
| 16 | +1. Decode the access token and review the following claims: |
| 17 | + |
| 18 | + - `aud` (Audience) |
| 19 | + - `iss` (Issuer) |
| 20 | + - `kid` (Key ID) |
| 21 | + |
| 22 | + > [!NOTE] |
| 23 | + > You can decode access tokens using [https://jwt.ms](https://jwt.ms). |
| 24 | +
|
| 25 | +## Step 2: Validate the audience claim of the access token |
| 26 | + |
| 27 | +If you send a Microsoft Graph access token to a non-Microsoft Graph resource provider, you get a signature validation error. Only Microsoft Graph can validate such token. The value of a Microsoft Graph token's `aud` claim is one of the following: |
| 28 | + |
| 29 | +- `https://graph.microsoft.us` |
| 30 | +- `https://graph.microsoft.us/` |
| 31 | +- `https://graph.microsoft.com` |
| 32 | +- `https://graph.microsoft.com/` |
| 33 | +- `https://dod-graph.microsoft.us` |
| 34 | +- `https://dod-graph.microsoft.us/` |
| 35 | +- `00000003-0000-0000-c000-000000000000` |
| 36 | + |
| 37 | +To resolve the signature validation error, ensure the correct access token is acquired for the resource provider and its `aud` claim is expected by the resource provider. |
| 38 | + |
| 39 | +The audience claim of an access token is determined by the `scope` parameter that's sent in the request when acquiring access tokens. For example, to get an access token for `https://api.contoso.com`, use a scope like `https://api.contoso.com/read`. |
| 40 | + |
| 41 | +For more information, see [Configure an application to expose a web API](/entra/identity-platform/quickstart-configure-app-expose-web-apis). |
| 42 | + |
| 43 | +## Step 3: Validate the signing key |
| 44 | + |
| 45 | +For other scenarios, the resource provider determines where to get the signing keys based on the OpenId Connect Metadata configuration and which signing key to use based on the `kid` claim of an access token. You can configure the OpenId Connect Metadata on the resource provider such as your custom API or API Authentication layer. |
| 46 | + |
| 47 | +If you use a Microsoft authentication library like Microsoft Authentication Library (MSAL) or Microsoft Identity Web to authenticate an application, the default `MetadataAddress` that points to the OpenId Connect Metadata configuration is like `https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration`. |
| 48 | + |
| 49 | +If you have configured a tenant ID, the `MetadataAddress` would be `https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration`. If you have configured an `Authority` like `https://login.microsoftonline.us/{tenant-id}`, the `MetadataAddress` would be `https://login.microsoftonline.us/{tenant-id}/v2.0/.well-known/openid-configuration`. |
| 50 | + |
| 51 | +The OpenId Connect Metadata endpoint includes the `jwks_uri` property (also known as discovery keys endpoint), which specifies the location of signing keys. Depending on which OpenId Connect Metadata endpoint is used, it returns a different URL for the `jwks_uri` property. Here's a table that provides a few examples: |
| 52 | + |
| 53 | +| Metadata endpoint | Discovery keys endpoint | |
| 54 | +| --- | --- | |
| 55 | +| `https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration` | `https://login.microsoftonline.com/common/discovery/v2.0/keys` | |
| 56 | +| `https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration`| `https://login.microsoftonline.com/{tenant-id}/discovery/v2.0/keys` | |
| 57 | +| `https://contosob2c.b2clogin.com/{tenant-id}/{policy}/v2.0/.well-known/openid-configuration` | `https://contosob2c.b2clogin.com/{tenant-id}/{policy}/discovery/v2.0/keys` | |
| 58 | + |
| 59 | +The discovery keys endpoint includes multiple signing keys. If you use a specific key manually instead of the signing key provided in the access token, or your cached key, the signature validation might not succeed due to regular key rotations. For more details, see [Signing key rollover in the Microsoft identity platform](/entra/identity-platform/signing-key-rollover). |
| 60 | + |
| 61 | +The content of discovery keys endpoint looks like this: |
| 62 | + |
| 63 | +```json |
| 64 | +"keys": [ |
| 65 | + { |
| 66 | + "kty": "RSA", |
| 67 | + "use": "sig", |
| 68 | + "kid": "<kid-value>", |
| 69 | + "x5t": "<x5t-value>", |
| 70 | + "n": "<n-value>", |
| 71 | + "e": "<e-value>", |
| 72 | + "x5c": [ |
| 73 | + "<x5c-value>" |
| 74 | + ], |
| 75 | + "issuer": "https://login.microsoftonline.com/{tenant-id}/v2.0" |
| 76 | + }, |
| 77 | +``` |
| 78 | + |
| 79 | +The `kid` claim of the access token must match one of the keys available on the discovery keys endpoint based on the `kid` property. If it doesn't match, there are two possible reasons: |
| 80 | + |
| 81 | +- Microsoft Entra ID and Azure Active Directory (AD) B2C use different signing keys. |
| 82 | +- The application is enabled for Security Assertion Markup Language (SAML) Single Sign-On (SSO). |
| 83 | + |
| 84 | +To resolve this mismatch, go to [Step 4: Validate the iss claim of the access token](#step-4-validate-the-iss-claim-of-the-access-token). |
| 85 | + |
| 86 | +## Step 4: Validate the iss claim of the access token |
| 87 | + |
| 88 | +### Scenario 1: Microsoft Entra ID and Azure AD B2C use different signing keys |
| 89 | + |
| 90 | +Check the `iss` claim of the access token. The `iss` claim indicates who issued the token: |
| 91 | + |
| 92 | +- For Microsoft Entra ID-issued tokens, the `iss` claim has one of these formats: |
| 93 | + |
| 94 | + - `https://sts.windows.net/{tenant-id}` (used for v1.0 tokens) |
| 95 | + - `https://login.microsoftonline.com/{tenant-id}/v2.0` (used for v2.0 tokens) |
| 96 | + |
| 97 | +- For Microsoft Entra External ID-issued tokens, the `iss` claim has this format: |
| 98 | + |
| 99 | + `https://{your-domain}.ciamlogin.com/{tenant-id}/v2.0/` |
| 100 | + |
| 101 | +- For Azure AD B2C-issued tokens, the `iss` claim has this format: |
| 102 | + |
| 103 | + `https://{your-domain}.b2clogin.com/tfp/{tenant-id}/{policy-id}/v2.0/` |
| 104 | + |
| 105 | +To avoid signature validation errors, configure your OpenID Connect Metadata correctly based on the token issuer: |
| 106 | + |
| 107 | +- For Microsoft Entra ID-issued tokens, make sure the OpenId Connect Metadata configuration looks like `https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration`. |
| 108 | + |
| 109 | + For more information, see [OpenID Connect on the Microsoft identity platform](/entra/identity-platform/v2-protocols-oidc). |
| 110 | + |
| 111 | +- For Microsoft Entra External ID-issued tokens, make sure the OpenId Connect Metadata configuration looks like `https://{tenant-domain}.ciamlogin.com/{tenant-id}/v2.0/.well-known/openid-configuration`. |
| 112 | + |
| 113 | + For more information, see [Set up your OpenID Connect identity provider](/entra/external-id/customers/how-to-custom-oidc-federation-customers#set-up-your-openid-connect-identity-provider). |
| 114 | + |
| 115 | +- For Azure AD B2C-issued tokens, make sure the OpenId Connect Metadata configuration looks like `<https://{your-domain}.b2clogin.com/{tenant-id}/{b2c-policy}/v2.0/.well-known/openid-configuration`. |
| 116 | + |
| 117 | + For more information, see [Web sign in with OpenID Connect in Azure Active Directory B2C](/azure/active-directory-b2c/openid-connect). |
| 118 | + |
| 119 | +### Scenario 2: The application is enabled for SAML SSO |
| 120 | + |
| 121 | +Assume that the access token is issued from Microsoft Entra ID instead of Azure AD B2C. When an application in Microsoft Entra ID is enabled for SAML SSO, the signing key used to sign tokens is the SAML signing certificate. So, when you look for the `kid` claim from the access token on the default discovery keys endpoint, usually `https://login.microsoftonline.com/common/discovery/v2.0/keys`, it might not be listed. |
| 122 | + |
| 123 | +We don't recommend using both OAuth2 and SAML for the same application. To resolve this issue, keep your application separate for OAuth2 and SAML by using one of the following methods: |
| 124 | + |
| 125 | +- Create a new app registration for OAuth2 (recommended method). |
| 126 | +- Convert the enterprise application to use OAuth2 only. |
| 127 | + |
| 128 | + To do so, disable SAML SSO by setting the `preferredSingleSignOnMode` property on the `servicePrincipal` to `null` or `oidc`. |
| 129 | + |
| 130 | +- Update the OpenId Connect Metadata configuration of the resource provider to include `?appid={application-id}`, like `https://login.microsoftonline.us/<tenant-id>/v2.0/.well-known/openid-configuration?appid=<application-id>`. |
| 131 | + |
| 132 | + > [!NOTE] |
| 133 | + > This solution is hard to implement and might not be possible depending on the resource provider. |
| 134 | + |
| 135 | +## Examples of OpenId Connect Metadata configurations |
| 136 | + |
| 137 | +Make sure you set the OpenId Connect Metadata configuration based on whether the access token is issued from Microsoft Entra ID or Azure AD B2C, or if adding `?appid={application-id}`. |
| 138 | + |
| 139 | +Generally, configuring the Microsoft Entra ID `Instance` and `Tenant`, or `Authority` correctly can resolve signature validation errors. |
| 140 | + |
| 141 | +- `Instance` |
| 142 | + |
| 143 | + Microsoft Entra ID instance would be `https://login.microsoftonline.com`. For more information about Microsoft Entra ID instances, see [National clouds](/entra/identity-platform/authentication-national-cloud). |
| 144 | + |
| 145 | +- `Tenant` |
| 146 | + |
| 147 | + Tenant would be `contoso.onmicrosoft.com`. You can also use the Directory ID or any verified domain. We recommend using the Directory ID or the initial domain provided by Microsoft Entra ID (such as `contoso.onmicrosoft.com`). |
| 148 | + |
| 149 | +- `Authority` |
| 150 | + |
| 151 | + If you configure an `Authority`, `Instance` and `Tenant` aren't needed as `Authority` follows this format: |
| 152 | + |
| 153 | + `{Instance}/{Tenant}` |
| 154 | + |
| 155 | + So, `Authority` would be like `https://login.microsoftonline.com/contoso.onmicrosoft.com`. |
| 156 | + |
| 157 | +Generally, the `MetadataAddress` is built based on the `Instance`/`Tenant`/`Authority` configuration and will automatically concatenate `/.well-known/openid-configuration` at the end. The following sections provide examples of manually specifying the `MetadataAddress`. |
| 158 | + |
| 159 | +### Example 1: Use Microsoft Identity Web |
| 160 | + |
| 161 | +```csharp |
| 162 | +services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) |
| 163 | + .AddMicrosoftIdentityWebApp( |
| 164 | + options => |
| 165 | + { |
| 166 | + Configuration.Bind("AzureAd", options); |
| 167 | + options.MetadataAddress = metadataAddress, |
| 168 | + |
| 169 | + }) |
| 170 | + .EnableTokenAcquisitionToCallDownstreamApi(options => Configuration.Bind("AzureAd", options), initialScopes) |
| 171 | + .AddMicrosoftGraph(Configuration.GetSection("GraphAPI")) |
| 172 | + .AddInMemoryTokenCaches(); |
| 173 | +``` |
| 174 | + |
| 175 | +For more details, see [Microsoft Identity Web customization](https://github.com/AzureAD/microsoft-identity-web/wiki/customization). |
| 176 | + |
| 177 | +### Example 2: Use ASP.NET standard framework |
| 178 | + |
| 179 | +- `UseWindowsAzureActiveDirectoryBearerAuthentication` |
| 180 | + |
| 181 | + Set the metadata to `https://login.microsoftonline.com/{tenant-id}/.well-known/openid-configuration`. |
| 182 | + |
| 183 | + ```csharp |
| 184 | + app.UseWindowsAzureActiveDirectoryBearerAuthentication( |
| 185 | + new WindowsAzureActiveDirectoryBearerAuthenticationOptions |
| 186 | + { |
| 187 | + MetadataAddress = metadataAddress, |
| 188 | + Tenant = ConfigurationManager.AppSettings["ida:Tenant"], |
| 189 | + ``` |
| 190 | + |
| 191 | +- `UseOpenIdConnectAuthentication` |
| 192 | + |
| 193 | + You can either set the `Authority` to `https://login.microsoftonline.com/{tenant-id}/v2.0`: |
| 194 | +
|
| 195 | + ```csharp |
| 196 | + public void Configuration(IAppBuilder app) |
| 197 | + { |
| 198 | + app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType); |
| 199 | + |
| 200 | + app.UseCookieAuthentication(new CookieAuthenticationOptions()); |
| 201 | + app.UseOpenIdConnectAuthentication( |
| 202 | + new OpenIdConnectAuthenticationOptions |
| 203 | + { |
| 204 | + // Sets the ClientId, authority, RedirectUri as obtained from web.config |
| 205 | + ClientId = clientId, |
| 206 | + Authority = authority, |
| 207 | + ``` |
| 208 | + |
| 209 | + Or set the `MetadataAddress` to `https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration`: |
| 210 | +
|
| 211 | + ```csharp |
| 212 | + public void Configuration(IAppBuilder app) |
| 213 | + { |
| 214 | + app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType); |
| 215 | + |
| 216 | + app.UseCookieAuthentication(new CookieAuthenticationOptions()); |
| 217 | + app.UseOpenIdConnectAuthentication( |
| 218 | + new OpenIdConnectAuthenticationOptions |
| 219 | + { |
| 220 | + // Sets the ClientId, authority, RedirectUri as obtained from web.config |
| 221 | + ClientId = clientId, |
| 222 | + MetadataAddress = metadataAddress, |
| 223 | + ``` |
| 224 | + |
| 225 | +### Example 3: Use Azure App Service authentication |
| 226 | + |
| 227 | +Refer to [Configure your App Service or Azure Functions app to use Microsoft Entra sign-in](/azure/app-service/configure-authentication-provider-aad). |
| 228 | + |
| 229 | +### Example 4: Use Azure API Management |
| 230 | + |
| 231 | +Refer to [Secure an Azure API Management API with Azure AD B2C](/azure/active-directory-b2c/secure-api-management?tabs=app-reg-ga). |
| 232 | + |
| 233 | +## References |
| 234 | + |
| 235 | +[Validate tokens](/entra/identity-platform/access-tokens#validate-tokens) |
| 236 | + |
| 237 | +[!INCLUDE [Azure Help Support](../../../includes/azure-help-support.md)] |
| 238 | + |
| 239 | + |
| 240 | + |
0 commit comments