Announcements
This site is in read only until July 22 as we migrate to a new platform; refer to this community post for more details.
Get hands-on experience with 20+ free Google Cloud products and $300 in free credit for new customers.

Verify JWT Using JWKS Invalid Key Configuration Error - Apigee X

Hi @dchiesa1 

Our enterprise is using Apigee X , and in order to validate an IDP minted token which is generated independent of Apigee, we are using the Verify JWT Policy. The policy is currently configured as below, where we are passing the JWKS url within the Public Key element. But we have been receiving the following error below. The value for uriref is fetched from a previous step in Assign Message Policy:

Error Response:

{
    "fault": {
        "faultstring": "Invalid Key configuration : policy(JWT-VerifyJWKS) element(PublicKey)",
        "detail": {
            "errorcode": "steps.jwt.InvalidKeyConfiguration"
        }
    }
}
 
Assign Message :

 

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage continueOnError="false" enabled="true" name="AM-AssignJWKS">
<DisplayName>AM-AssignJWKS</DisplayName>
<Properties/>
<AssignVariable>
<Name>kid_header</Name>
<Ref>jwt.JWT-DecodeJWT-KID.header.kid</Ref>
</AssignVariable>
<AssignVariable>
<Name>jwksurl</Name>
<Value>https://test.auth.highmark.com/oauth2/rest/security --header X-OAUTH-IDENTITY-DOMAIN-NAME: <value of kid>/Value>
</AssignVariable>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>

 

 

Verify JWT

 

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<VerifyJWT continueOnError="false" enabled="true" name="JWT-VerifyJWKS">
    <DisplayName>JWT-VerifyJWKS</DisplayName>
    <Algorithm>RS256</Algorithm>
    <!-- <Source>request.header.authorization</Source> -->
    <PublicKey>
        <JWKS uriRef="jwksurl"/>
    </PublicKey>
</VerifyJWT>

 

 

I have tried to hardcode value of kid in Assign Message policy, I have also tried to assign the value of variable that is having the value of the kid in the Assign Message policy but even that has not worked.
 

I am sharing the JWT token (expired) :

eyJraWQiOiJhcGlnZWUtZGVtby1hcGltIiwieDV0IjoicUd5V1QxUVQteW9zcHpmZzN4M2htOFkxcDNZIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL29hdXRocWEuaG1ocy5jb20iLCJhdWQiOlsiaHR0cHM6Ly9jZHNzb3Rlc3QuaGlnaG1hcmsuY29tOjQ0My9vYXV0aDIiLCJyZXNvdXJjZSIsImFiMCJdLCJleHAiOjE3MTExMDg4MjgsImp0aSI6IjhBZ1FjaEptLVlaTU5TNldhVGRHanciLCJpYXQiOjE3MTExMDUyMjgsInN1YiI6IjQyMzQ0NDctMDMwNC01NDM3LWE2NzQyNDQ0ZTRhNTM1NjU0MmY0ZDQ0NzU2NTY3M2QzZCIsImNsaWVudCI6IjQyMzQ0NDctMDMwNC01NDM3LWE2NzQyNDQ0ZTRhNTM1NjU0MmY0ZDQ0NzU2NTY3M2QzZCIsInNjb3BlIjpbInJlc291cmNlLlJFQUQiXSwiZG9tYWluIjoiYXBpZ2VlLWRlbW8tYXBpbSIsInVpZCI6IiIsImhta1Rva2VuVHlwZSI6IkNsaWVudElEIiwibWFpbCI6IiIsImdpdmVuTmFtZSI6IiIsInNlc3Npb25JZCI6IiIsInNuIjoiIiwiaXNtZW1iZXJvZiI6IiIsInBybiI6IjQyMzQ0NDctMDMwNC01NDM3LWE2NzQyNDQ0ZTRhNTM1NjU0MmY0ZDQ0NzU2NTY3M2QzZCIsInJlc1NydkF0dHIiOiJSRVNPVVJDRUNPTlNUIiwiaG1rVG9rZW5WZXJzaW9uIjoidjQifQ.nJIi95radCKvclvam_V-wJMkePsF9emoMhGBqj-DI4z-8R6toRqGdTESTWKnUu3lvHXZzt1z3BNaSs9cKGog7_loNYKixwPTqcoBK4VjPhL7SsV8_H5YkrOqfBAWsfsOG3yfsrMD4f3swTukRR6UDv9Gq2XTdULe5y8CK56FseNBy-iILqYr4gf8QW1z7KRyigX-mRCgERR1H0TnjnlkCp6gm-2U18ioxyv4t22iB6NUdCocDd9ayEL2JF_dbpg-qJaQnYgsaWe5Iof4tIM175AjnopFsTpCpWujeeCmuPud_xrXALX3okrlfvstVuM5Uym5XPfi3VCsla0-46IiJA

 

Request your inputs as what I could be missing or done wrong.

Thanks,

Debjit

Solved Solved
2 13 769
3 ACCEPTED SOLUTIONS

Hi Debjit

I am unclear on how the VerifyJWT Policy can use the proxy from Step 1. The policy has options to pass a static uri or an uriRef, but am unclear on how the policy can leverage this proxy.

If I understand what you've done, you have a proxy that accepts a request like

https://test.auth.highmark.com/jwks-getter?domain=apigee-demo-apim

That's a static URL. You can just use that directly in your VerifyJWT policy.

 

<VerifyJWT continueOnError="false" enabled="true" name="JWT-VerifyJWKS">
    <DisplayName>JWT-VerifyJWKS</DisplayName>
    <Algorithm>RS256</Algorithm>
    <!-- <Source>request.header.authorization</Source> -->
    <PublicKey>
        <JWKS uri="https://test.auth.highmark.com/jwks-getter?domain=apigee-demo-apim"/>
    </PublicKey>
</VerifyJWT>

 

If you are thinking that you need to support. multiple different oauth domains with the same policy, that means you need to have a dynamic (determined at runtime) uri. In that case you can set a variable, and use uriRef. Set the variable in a policy like

 

<AssignMessage name='AM-OAuth-JWKS-URI'>
  <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
  <AssignVariable>
    <Name>oauth_domain_fulluri</Name>
    <Template>https://test.auth.highmark.com/jwks-getter?domain={desired_oauth_domain}</Template>
  </AssignVariable>
</AssignMessage>

 

And then the VerifyJWT would be like this;

 

<VerifyJWT continueOnError="false" enabled="true" name="JWT-VerifyJWKS">
    <DisplayName>JWT-VerifyJWKS</DisplayName>
    <Algorithm>RS256</Algorithm>
    <!-- <Source>request.header.authorization</Source> -->
    <PublicKey>
        <JWKS uriRef="oauth_domain_fulluri"/>
    </PublicKey>
</VerifyJWT>

 

Also, let me clarify what I said earlier

Embed the Identity domain name as a path segment, rather than a header.

I was suggesting a Path segment, not a query param. So the inbound URL would look like

htt​ps://test.auth.highmark.com/oauth2/apigee-demo-apim/.well-known/jwks

And in the jwks wrapper proxy, you would use ExtractVariables to extract the path segment. Like this:

 

<ExtractVariables name='EV-OAuth-Domain'>
   <Source>request</Source>
   <VariablePrefix>extracted</VariablePrefix>
   <URIPath>
      <!-- put the extracted value into extracted.oauth_domain -->
      <!-- NB: The Pattern is matched against pathsuffix (what comes AFTER the basepath) -->
      <Pattern ignoreCase='false'>/{oauth_domain}/.well-known/jwks</Pattern>
   </URIPath>
   <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</ExtractVariables>

 

And then you have a variable extracted.oauth_domain , holding the value that you could set into the required header, X-OAUTH-IDENTITY-DOMAIN-NAME , with an AssignMessage.

THIS WILL WORK. Your query param approach will work, too, though it feels slightly less elegant to me.

But if I were the IDP architect on this system, I would want to avoid the wrapper proxy entirely. Ideally, the JWKS endpoint should not require that header. The JWKS should "natively" extract the domain from a URL path. Wrapping an Apigee proxy around that endpoint as a wrapper, helps, but the ideal solution would be to modify that JWKS endpoint at the source. I understand that might not be quickly feasible!

View solution in original post

Hi Dino,

Thank you for sharing the steps in detail, I will keep you posted how it goes. I am sorry but the decisions to update the JWKS URLs is with the IDP team, I will keep you posted about any updates on this front also.

 

Regards,

Debjit

View solution in original post

I just read about this in Assign Message Policy - AssingVariable - Templates

https://cloud.google.com/apigee/docs/api-platform/reference/message-template-intro#targetendpoint-el... 

Does that mean in Assign Message policy we can proxy another API which has as hostname as https://api-{env}.highmark.com

If yes will that be applicable to solution you have suggested and help. Could you please share any samples if available that helps to call proxy from the Assign Message if its possible.

View solution in original post

13 REPLIES 13