Dynamic 'kid' Usage in Azure APIM Validate-JWT Policy
We currently use hardcoded exponent and modulus values within the
Azure API Management
Azure Policy
-
Khadeer Ali 1,400 Reputation points • Microsoft Vendor
2024-12-19T18:39:15.78+00:00 Welcome to the Microsoft Q&A Platform!
Thank you for reaching out about the dynamic JWT validation issue in Azure API Management (APIM). Upon review, it appears the error you encountered—"Exactly one of a value or certificate-id or n/e pair must be specified for the issuer signing key"—is caused by a missing modulus (n) and exponent (e) pair in the <issuer-signing-keys> element.Issue and Resolution:
- In your current implementation, you are correctly fetching the modulus (n) and exponent (e) for kid1 from the JWKS endpoint. However, the error occurs because the policy expects either a key element containing n and e, or a certificate-id for validation.
- The solution might be to modify the
<issuer-signing-keys>
element to include themodulus
andexponent
values forkid1
directly, as you’ve already fetched them dynamically.<issuer-signing-keys> <key n="@((string)context.Variables["modulus1"])"e="@((string)context.Variables["exponent1"])" /> </issuer-signing-keys>
By ensuring that the <issuer-signing-keys> element includes the required modulus and exponent for the corresponding kid, the validation should work as expected.
Let me know if you need any further clarification or assistance with this.
-
Aaron Bowe 0 Reputation points
2024-12-20T13:54:55.2666667+00:00 Thanks for your reply.
We initially attempted what you suggested (using the exponent and modulus) but were not successful. We believe that was because, according to Microsoft’s documentation, policy expressions aren’t allowed for the exponent or modulus. That’s why we’re attempting to get this to work with the ‘kid’. Are we misinterpreting this documentation.
-
Aaron Bowe 0 Reputation points
2024-12-23T14:33:32.7966667+00:00 I've found this will work. Do you have any suggestions for improvements?
<policies>
<inbound> <base /> <send-request mode="new" response-variable-name="jwksResponse" timeout="10" ignore-error="true"> <set-url>https://evkeys.xxxxxxxxx.com/auth/jwks</set-url> <set-method>GET</set-method> </send-request> <!-- Get the two kid values from the JWT and convert them to base64 --> <set-variable name="jwks" value="@((JObject)((IResponse)context.Variables["jwksResponse"]).Body.As<JObject>())" /> <set-variable name="kid1" value="@((string)((JObject)context.Variables["jwks"])["keys"][0]["kid"])" /> <set-variable name="kid2" value="@((string)((JObject)context.Variables["jwks"])["keys"][1]["kid"])" /> <set-variable name="base64kid1" value="@{ var kid1 = context.Variables.GetValueOrDefault<string>("kid1"); var bytes = System.Text.Encoding.UTF8.GetBytes(kid1); return System.Convert.ToBase64String(bytes); }" /> <set-variable name="base64kid2" value="@{ var kid2 = context.Variables.GetValueOrDefault<string>("kid2"); var bytes = System.Text.Encoding.UTF8.GetBytes(kid2); return System.Convert.ToBase64String(bytes); }" /> <validate-jwt header-name="Authorization" require-expiration-time="true" require-scheme="Bearer" require-signed-tokens="true" output-token-variable-name="xxxxxxxxx-jwt-token"> <issuer-signing-keys> <key>@((string)context.Variables["base64kid1"])</key> <key>@((string)context.Variables["base64kid2"])</key> </issuer-signing-keys> <issuers> <issuer>https://auth.xxxxxxxxx.com</issuer> </issuers> <required-claims> <claim name="exp" match="all" /> <claim name="iss" match="all" /> <claim name="x_query_parameter" match="all"> <value>@(System.Convert.ToBase64String(Encoding.UTF8.GetBytes((string)context.Request.Url.QueryString.TrimStart('?'))))</value> </claim> <claim name="x_target_client" match="all"> <value>{{ev-non-prod-dev-x-target-client}}</value> </claim> </required-claims> </validate-jwt> </inbound> <backend> <base /> </backend> <outbound> <base /> </outbound> <on-error> <base /> </on-error>
</poli
-
Khadeer Ali 1,400 Reputation points • Microsoft Vendor
2024-12-23T17:34:00.53+00:00 @Aaron Bowe
Thank you for sharing your solution. It’s great to see this approach leveraging send-request to dynamically retrieve the JWKS and generate the keys for validation. The use of dynamically fetching kid values, encoding them to Base64, and passing them into the <validate-jwt> policy aligns with the requirement to dynamically handle key validation.
Sign in to comment