How to Validate an azlogin DefaultCredential JWT token using Azure Api Management <Validate-Jwt> policy.

Vinit Sawant 0 Reputation points
2024-01-20T14:36:52.4433333+00:00

Hello Reader,
I have a python notebook with the following 2 blocks of code:

code block 1: !az login
code block 2 :

from azure.identity import DefaultAzureCredential

credential = DefaultAzureCredential()
token = credential.get_token("https://graph.microsoft.com/.default")
auth_token = token.token
print(auth_token)

The 3rd code block is a call to APIM management url with header authorization set equal to the above auth_token as below.

headers = {
        "Content-Type" : "application/json",
        "Authorization" : f"Bearer {auth_token}"
    }

I want to validate the token that gets generated from the 2nd cell output using the API Management <validate-jwt> policy. The policy I currently have in my APIM instance is as below:

<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Token is Invalid" output-token-variable-name="valid-jwt">
            <openid-config url="https://login.microsoftonline.com/{{aad-tenant}}/v2.0/.well-known/openid-configuration" />
            <audiences>
                <audience>https://graph.microsoft.com</audience>
            </audiences>
            <issuers>
                <issuer>https://sts.windows.net/xxxxx0e4-xxxx-xxxxx-xxxx-58830e4axxxxx/</issuer>
            </issuers>
            <required-claims>
                <claim name="aud" match="any">
                    <value>https://graph.microsoft.com</value>
                </claim>
            </required-claims>
        </validate-jwt>
        <set-variable name="user_oid" value="@(((Jwt)context.Variables["valid-jwt"]).Claims["oid"][0])" />

I read the documentation about validate-jwt that it needs various optional fields like issuer-signing-key
being one of them. I wonder is it something to do with that. Also when decoded the token using jwt.ms it has a .[signature] part to it.

If you notice the last line of the policy, I am trying to extract the "oid" Claim from the validated jwt token stored in the variable named valid-jwt. I am pretty sure that the syntax is wrong in that expression as well.

Long Story Short, I wanna extract the "oid" claim from the token that is generated from the code block 2 output after validating that the token is a valid token.

The error that i am getting is as below:

validate-jwt (-3.552 ms)
{
    "message": "JWT Validation Failed: IDX10511: Signature validation failed. Keys tried: 'Microsoft.IdentityModel.Tokens.X509SecurityKey, KeyId: 'xxxxxxxxxxxxxxxxxxxx', InternalId: 'xxxxxxxxxxxxxxxxxxxx'. , KeyId: xxxxxxxxxxxxxxxxxxxx\r\n'. \nNumber of keys in TokenValidationParameters: '4'. \nNumber of keys in Configuration: '0'. \nMatched key was in 'TokenValidationParameters'. \nkid: 'xxxxxxxxxxxxxxxxxxxx'. \nExceptions caught:\n ''.\ntoken: 'hidden'System.IdentityModel.Tokens.Jwt.JwtSecurityToken' is hidden. For more details, see https://aka.ms/IdentityModel/SecurityArtifactLogging.]'. See https://aka.ms/IDX10511 for details.."
}
Azure API Management
Azure API Management
An Azure service that provides a hybrid, multi-cloud management platform for APIs.
2,447 questions
{count} votes

3 answers

Sort by: Most helpful
  1. Konstantinos Passadis 19,586 Reputation points MVP
    2024-01-20T20:08:58.52+00:00

    Hello @Vinit Sawant !  

    Welcome to Microsoft QnA!

       The error IDX10511: Signature validation failed suggests that the JWT token's signature cannot be validated against the keys provided by the OpenID Connect discovery document specified in your <validate-jwt> policy.

      Please validate that token's aud (audience) and iss (issuer) claims match what's expected in your APIM policy.

    The audience you're using (https://graph.microsoft.com) should match the token's intended audience.

    Also the issuer should match the issuer URL provided in your policy.

     If the validation passes focus on the relation of the Policy and the request   Validation : decode the token at jwt.ms to check the claims present in it. If the token validation fails, the policy won't execute , so make sure you pass.

     Make sure you followed the documentation -->

     References :

     https://robertoprevato.github.io/Validating-JWT-Bearer-tokens-from-Azure-AD-in-Python/ https://learn.microsoft.com/en-us/entra/identity-platform/id-tokens#validate-tokens I hope this helps!

    The answer or portions of it have been assisted by AI Source: ChatGPT Subscription Kindly mark the answer as Accepted and Upvote in case it helped!

    Regards

       


  2. Konstantinos Passadis 19,586 Reputation points MVP
    2024-01-21T09:22:32.7266667+00:00

    Hello @Vinit Sawant !  

    Add this please and retry :

    https://sts.windows.net/<TENANT-ID>/v2.0/issuer
    
    
    

    Kindly mark the answer as Accepted and Upvote in case it helped! Regards


  3. MuthuKumaranMurugaachari-MSFT 22,441 Reputation points Moderator
    2024-01-29T21:27:16.6433333+00:00

    Vinit Sawant Thanks for posting your question in Microsoft Q&A. Sorry for the delay in our response. From the description above, you are facing error IDX10511: Signature validation failed. Keys tried 'Microsoft.IdentityModel.Tokens.X509SecurityKey, KeyId: xxxxx with validate-jwt policy.

    Please follow the solution described in https://techcommunity.microsoft.com/t5/azure-paas-blog/protect-api-s-using-oauth-2-0-in-apim/ba-p/2309538 article and I am posting the summary below for reference:


    Solution:
    If you look at the metadata for the config url (https://login.microsoftonline.com/common/.well-known/openid-configuration) you will find a jwks_uri property inside the resulting json. This uri will point to a set of certificates used to sign and validate the jwt's.  You may find that the keyId (in this sample "CtTuhMJmD5M7DLdzD2v2x3QKSRY") does exist there. 

    Something like this:

    {
    "keys": [{
    "kty": "RSA",
    "use": "sig",
    "kid": "
    "x5t": "CtTuhMJmD5M7DLdzD2v2x3QKSRY",
    "n": "18uZ3P3IgOySln……",
    "e": "AQAB",
    "x5c": ["MII….."]
    

     So it seems that it should be able to validate the signature. If you look at the decoded jwt you may see something like this:

    {
    "typ": "JWT",
    "alg": "RS256",
    "x5t": "CtTuhMJmD5M7DLdzD2v2x3QKSRY",
    "kid": "CtTuhMJmD5M7DLdzD2v2x3QKSRY"
    }
    .{
    "aud": "00000003-0000-0000-c000-000000000000",
    "iss": "[https://sts.windows.net/<tenantID>/](https://sts.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47/)",
    "appid": "1950a258-227b-4e31-a9cf-717495945fc2",
    **"nonce": "da3d8159-f9f6-4fa8-bbf8-9a2cd108a261",**
    
    

    There's a nonce in play here.  

    This requires extra checking that validate-jwt does not do.  Getting a token for the Graph api and Sharepoint may emit a nonce property.  A token used to make calls to the Azure management api, however, will not have the nonce property.

    The 'nonce' is a mechanism, that allows the receiver to determine if the token was forwarded. The signature is over the transformed nonce and requires special processing, so if you try and validate it directly, the signature validation will fail.

    The validate jwt policy is not meant to validate tokens targeted for the Graph api or Sharepoint.  The best thing to do here is either remove the validate jwt policy and let the backend service validate it or use a token targeted for a different audience.


    So, unfortunately, validate-jwt policy cannot be used in such scenarios. We do have an open item: https://github.com/MicrosoftDocs/azure-docs/issues/80018 to update the doc and I will follow up with our product team internally to add this note. Sorry for the inconvenience caused.

    I hope this helps and let us know if you have any questions.


    If you found the answer to your question helpful, please take a moment to mark it as Yes for others to benefit from your experience. Or simply add a comment tagging me and would be happy to answer your questions.


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.