Validate JWT in Azure APIM policy - azure

In Azure APIM, I am trying to create a policy that will validate a JWT. No matter what I try, I always get a "401: Invalid JWT" error. Does anyone know what I'm doing wrong? (Maybe I'm not using the right signing key?)
My base64 encoded security key is Zm9v.
I create sample token at jwt.io and so my Authorization header is:
Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.Bm8tu4m18oA96xwhBL8AV_4hRpIU6OrK5UaOmGqBEsk
Here's the policy I am using:
<policies>
<inbound>
<base />
<validate-jwt
header-name="Authorization"
require-expiration-time="false"
require-scheme="Bearer"
>
<issuer-signing-keys>
<key>Zm9v</key>
</issuer-signing-keys>
</validate-jwt>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
HTTP Response:
cache-control: private
content-length: 48
content-type: application/json
ocp-apim-trace-location: https://xxxxxxx
vary: Origin
{
"statusCode": 401,
"message": "Invalid JWT."
}

Problem was my key size was too small.
When testing the API in Azure, there is a Trace tab, but it is missing the On Error section.
You have to go to the Message tab. There is an ocp-apim-trace-location which will show the full trace.
It turns out the key size I was using was too small. It was only 24 and needs to be at least 128.

The token you provided is invalid signature. Go to jwt.io to check your token firstly.
The policy you provided it right. For more details, you could refer to this article.

Related

Azure APIM with certificate authentication error using .pfx certificate

Helle, everyone.
I am experiencing issue with configuring APIm operation with InBound policy, which handled calls to remote endpoint. I have saved certificate which was provided to me by external service and using thumbprint in policie. Remote endpoint validates requests using certificate.
<policies>
<inbound>
<base />
<send-request mode="new" response-variable-name="result" timeout="300" ignore-error="false">
<set-url>https://ip:port/path</set-url>
<set-method>POST</set-method>
<set-header name="Accept" exists-action="override">
<value>*/*</value>
</set-header>
<set-header name="Content-Type" exists-action="override">
<value>application/xml</value>
</set-header>
<set-body>#(context.Request.Body.As<string>())</set-body>
<authentication-certificate thumbprint="thubprint" password="password" />
</send-request>
<return-response response-variable-name="result" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
But as a response I am getting 500 error
send-request (259.918 ms)
{
"messages": [
"Error occured while calling backend service.",
"The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.",
"The remote certificate is invalid according to the validation procedure."
]
}
Thanks beforehands. Would appreciate any help.
As discussed in the comments, adding gist as a community wiki answer to help community members who might face a similar issue.
But as a response I am getting 500 error
If you are using self-signed certificates, you will need to disable certificate chain validation for API Management to communicate with the backend system. Otherwise, it will return a 500 error code.
Try the following code snippet taken from the document:
$context = New-AzApiManagementContext -resourcegroup 'ContosoResourceGroup' -servicename 'ContosoAPIMService'
New-AzApiManagementBackend -Context $context -Url 'https://contoso.com/myapi' -Protocol http -SkipCertificateChainValidation $true
Note: As of now disabling certificate chain validation is only possible for backend policy.
You can refer to Azure API Management - Validate incoming client certificate and Send cert to backend, Is disabling Validate certificate chain safe? and Protect your APIs with Azure API Management

Accessing API Management API from Excel using organizational account

In our organization we have some people that uses Excel to access our APIs. We would like the APIs to be exposed by API Management and to be authenticated using Azure Active Directory.
In excel this can be achieved by using an "Organizational account", but currently I get the message "We couldn't authenticate with the credentials provided. Please try again"
I have followed this guide in order to set up an Active Directory Registered application and configured API Management accordingly.
One additional step I have done is to add the "WWW-Authenticate" header in following in API management configuration, in order to trigger Excel to do authentication against our AD tenant:
<policies>
<inbound>
<base />
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
<openid-config url="https://login.microsoftonline.com/<tenant-id>/v2.0/.well-known/openid-configuration" />
<required-claims>
<claim name="aud">
<value>expected-aud</value>
</claim>
</required-claims>
</validate-jwt>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<choose>
<when condition="#(context.Response.StatusCode == 401)">
<set-header name="WWW-Authenticate" exists-action="override">
<value>Bearer realm="<tenant-id>", error="invalid_token", error_description="Access Token missing or malformed.", authorization_uri="https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/authorize", client_id="<client-id>"</value>
</set-header>
</when>
</choose>
<base />
</on-error>
When looking at the HTTP requests in Fiddler, the a request made to login.microsoft.com actually retrieves a token. This is the body of the response:
{
"token_type": "Bearer",
"scope": "some-scope user_impersonation",
"expires_in": "3599",
"ext_expires_in": "3599",
"expires_on": "1600932873",
"not_before": "1600928973",
"resource": "https://api-management-host",
"access_token": "<access-token>",
"refresh_token": "<refresh-token>",
"id_token": "<id-token>"
}
But the following request to API management does not contain the token - the authorization header only has the keyword Bearer:
Authorization: Bearer
Anyone out there that have any experience with this scenario - or can help me solve this issue?

Error adding a JWT inbound policy: Error in element 'validate-jwt':Certificate '' could not be resolved

When using Azure APIM to add a inbound policy to verify a JWT, the config editor throws the following error:
One or more fields contain incorrect values: Error in element 'validate-jwt' on line 16, column 10: Certificate '' could not be resolved.
I can see it's the issuer-signing-keys node causing the problem as removing it allows it to save.
Here is the example of the policies file:
<policies>
<inbound>
<base />
<validate-jwt header-name="Authorization" require-scheme="Bearer">
<issuer-signing-keys>
<key>YmVlZg==</key>
</issuer-signing-keys>
</validate-jwt>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
Thanks in advance for any help
Credit to #Mukesh Kumar
This is a bug we reported on Friday 19th Jun 2020. Recently Microsoft has rolled out a new release that applies to all new instances of APIM. So if you have previously created APIM instance then it would work. We are still awaiting MS to provide hotfix.

Azure API Management caching policy

In my Azure API Managemenent I'm defining a header based caching policy at API level.
The policy is quite simple:
<policies>
<inbound>
<check-header name="token" failed-check-httpcode="400" failed-check-error-message="Token header is missing" ignore-case="true" />
<cache-lookup vary-by-developer="false" vary-by-developer-groups="false" downstream-caching-type="none">
<vary-by-header>token</vary-by-header>
</cache-lookup>
<base />
</inbound>
<backend>
<forward-request />
</backend>
<outbound>
<cache-store duration="3600" />
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
This works ok in the case my downstream returns a 200 with a body - next request with same header token will hit the cache and the response will be returned from the API Management cache.
However is a error code is returned by the downstream (eg: 401 Unauthorized) that response is not cached by the API Management (confirmed by the tracing I've enabled on the API Management).
I was under the impression that whole responses are cached, but this doesn't seem to be the case...
Can somebody let me know if it's possible to cache responses also in case of unsuccessful http codes and if yes point me to some doc - I've been googling all day yesterday, but was unable to find more.
Thanks in advance!
This is by design. If you look into traces you should see message there "Backend service responed with the status code of 401 rather than 200 OK. Cache Store policy was not applied." The reasoning is that at APIM level we assume that non 200 responses are more transient than 200.
Say that client gets 401, goes on to do whatever to make sure that token is allowed to do the operation and retries the call. And still gets 401 from cache until cache expires.
That certainly may be added as an extra configuration option on a policy: http://aka.ms/apimwish
You could workaround that by using cache-lookup-value and cache-store-value. I.e. in the outbound section if you get 401 store some value in cache using cache-store-value to keyed with token. And in the inbound before cache-lookup do cache-lookup-value with token and see if you get value stored earlier. If you do you can generate 401 response right in place.

Invoking API fails from web page, though succeeds in Test pages

I've create a API populated from a swagger.json file and verified it works in the Test UI. The test UI request succeeds showing the headers passed below.
POST https://apiforqubo.azure-api.net/api/Qubo HTTP/1.1
Host: apiforqubo.azure-api.net
Content-Type: application/json
Ocp-Apim-Subscription-Key: ••••••••••••••••••••••••••••••••
Ocp-Apim-Trace: true
I've added a CORS policy for all operations. This is now updated to reflect the answer below.
The updated policy is:
<policies>
<inbound>
<base />
<cors allow-credentials="true">
<allowed-origins>
<origin>https://apiforqubo.developer.azure-api.net</origin>
</allowed-origins>
<allowed-methods>
<method>POST</method>
<method>GET</method>
<method>PUT</method>
</allowed-methods>
</cors>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
When I try to execute the API from the web page that's generated for the API at: https://apiforqubo.developer.azure-api.net/api-detail, the request fails with the error:
Unable to complete the request
Since the browser initiates the request, it requires Cross-Origin Resource Sharing (CORS) enabled on the server.
What am I missing?
UPDATE: policy statement to reflect specific website as suggested by Vitaliy Kurokhtin in the comments.
Regards,
Rajesh
You've configured it to allow CORS requests only from https://azure-api.net, not from https://apiforqubo.developer.azure-api.net. Either use full URL or wildcard:
<origin>https://*.azure-api.net/</origin>
Please add allowed-headers policy element in your policy in APIM

Resources