Search code examples
azureapioauth-2.0azure-api-managementjwt

"JWT Validation Failed: JWT not present.." in Azure API Management Service


For reference I am attempting to reproduce the solution talked about here: https://www.tech-findings.com/2020/02/securing-logic-app-with-azure-active-directory.html to use API Management to secure an Azure Logic App.

I am getting a JWT Error. When I visit the app url in the browser it gives:

{ "statusCode": 404, "message": "Resource not found" }

In the API Management Service test I get:

HTTP/1.1 401 Unauthorized

Following the trace through it shows:

validate-jwt (-0.111 ms)
{
    "message": "JWT Validation Failed: JWT not present.."
}

I did some googling and tried the solutions at: JWT validation failure error in azure apim and https://learn.microsoft.com/en-us/answers/questions/108008/azure-apim-jwt-token-validation-policy.html

Here is the inbound policy of from the API Management design:

<policies>
    <inbound>
        <base />
        <set-method id="apim-generated-policy">POST</set-method>
        <rewrite-uri id="apim-generated-policy" template="/request/paths/invoke//?api-version=2016-06-01&amp;sp=/triggers/request/run&amp;sv=1.0&amp;sig={{[[LOGIC APP NAME]]_request-invoke_XXXXXXXXXXXXXXXXXXXXXXXX}}" />
        <validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Request is not authorized or token failed" require-expiration-time="false" require-scheme="Bearer" require-signed-tokens="true">
            <openid-config url="https://login.windows.net/[[TENANT NAME]].onmicrosoft.com/.well-known/openid-configuration" />
            <audiences>
                <audience>[[THE ID OF A REGISTERED APP]]</audience>
            </audiences>
        </validate-jwt>
        <set-header name="Authorization" exists-action="delete" />
        <set-header name="apim-generated-policy" exists-action="delete" />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

This is the manifest of the registered app:

{
    "id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "acceptMappedClaims": null,
    "accessTokenAcceptedVersion": 2,
    "addIns": [],
    "allowPublicClient": null,
    "appId": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "appRoles": [],
    "oauth2AllowUrlPathMatching": false,
    "createdDateTime": "2020-12-22T19:48:36Z",
    "disabledByMicrosoftStatus": null,
    "groupMembershipClaims": null,
    "identifierUris": [
        "api://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    ],
    "informationalUrls": {
        "termsOfService": null,
        "support": null,
        "privacy": null,
        "marketing": null
    },
    "keyCredentials": [],
    "knownClientApplications": [],
    "logoUrl": null,
    "logoutUrl": null,
    "name": "LabsTestApp",
    "oauth2AllowIdTokenImplicitFlow": false,
    "oauth2AllowImplicitFlow": false,
    "oauth2Permissions": [],
    "oauth2RequirePostResponse": false,
    "optionalClaims": null,
    "orgRestrictions": [],
    "parentalControlSettings": {
        "countriesBlockedForMinors": [],
        "legalAgeGroupRule": "Allow"
    },
    "passwordCredentials": [],
    "preAuthorizedApplications": [],
    "publisherDomain": "[[TENANT NAME]].onmicrosoft.com",
    "replyUrlsWithType": [],
    "requiredResourceAccess": [],
    "samlMetadataUrl": null,
    "signInUrl": null,
    "signInAudience": "AzureADandPersonalMicrosoftAccount",
    "tags": [],
    "tokenEncryptionKeyId": null
}

Hoping you can help out - point me in the right direction.


Solution

  • For this question, there are more than one problem in your steps.

    1. You mentioned the error { "statusCode": 404, "message": "Resource not found" } when you request the url in browser. The reason is when you request it in browser, it request with Get method but the url should be request with Post method. So it shows 404 not found.

    2. When you test in API Management service, it shows 401 Unauthorized. The reason for this error is you did not provide the access token or the access token you provided is invalid. The steps in the document you mentioned are incomplete, please refer to the steps below:

    1). First please make sure you have completed all of the steps in the document you provided.

    2). Then go to the app you registered in azure ad and click "Manifest" tab, add a appRole in the json of "Manifest". enter image description here You can specify a name(anything you want) for this role, I named the role as Writer as the screenshot above shows. And you can also specify a "id"(in GUID format) as the value of the id field in appRole. For more details of add appRole, you can refer to this document.

    3). You need to register another app in azure ad as the client app. Do same register operation as your document shows to register the other app, I registered the app and named huryGetToken4. Go to this app and click "API permissions" tab, click "Add a permission" and find the original app you registered, then add the permission Writer. enter image description here enter image description here

    After add the Writer permission, you also need to click "Grant admin consent for xxx". enter image description here

    Then click "Certificates & secrets" tab, click "New client secret" to generate a client secret. Copy this secret because it will just show one time. enter image description here

    4). Then you need to get access token, please refer to the screenshot below to request for access token. enter image description here In the screenshot above, you need to replace the <tenant id> with your tenant id in the host url. And you also need to input the first three parameters. The last parameter grant_type is static.

    5). Request for the access token, you will get the response like below screenshot. enter image description here Copy the value of access_token and paste it to this page to decode the token, you can see the claim roles with Writer permission in it. This claim is what you need to check in the <validate-jwt> policy in your APIM. enter image description here

    6). Go to your apim and click the pencil icon of validate-jwt policy. enter image description here

    7). Edit the "Reauired claims" like screenshot below: enter image description here

    8). After that, you can test the api in APIM service. Add a header with key: Authorization, value: Bearer <your access token>(note there is a blank between Bearer and access token). enter image description here