Could not find a matching Public Key: policy(verifyJWT) -Error

Hello ,

Below is the policy snippet for verify JWT :

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<VerifyJWT async="false" continueOnError="false" enabled="true" name="verifyJWT">
<Algorithm>RS256</Algorithm>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
<PublicKey>
<JWKS uri=" Cert url"/>
</PublicKey>
<AdditionalHeaders/>
<IgnoreCriticalHeaders>false</IgnoreCriticalHeaders>
<AdditionalClaims/>
<IgnoreIssuedAt>false</IgnoreIssuedAt>
</VerifyJWT>

and the content of uri is given below

{"keys":[{"kty":"RSA","use":"sig","kid":"2","x5c”:[“*********\u003d\u003d"]},,{"kty":"RSA","use":"sig","kid":"1","x5c”:[“*****************************”]}]}

When a JWT Token is sentfor verification, below error is displayed .

jwt.verifyJWT.error 

Could not find a matching Public Key: policy(verifyJWT)
{"fault":{"faultstring":"Could not find a matching Public Key: policy(verifyJWT)","detail":{"errorcode":"steps.jwt.NoMatchingPublicKey"}}}
Solved Solved
0 9 1,452
2 ACCEPTED SOLUTIONS

You can try using this Java callout to transform your JWKS:

https://github.com/DinoChiesa/Apigee-Java-Transform-Jwks

View solution in original post

Hi @dchiesa1 ,

Thanks for the API Bundle. We will try from our end will update the status

Regards,

Suma

View solution in original post

9 REPLIES 9

What kid is present in the JWT header?

Apigee will select a JWK from the JWKS, based on the kid field in the JWT header. ( kid stands for Key ID). Your JWKS has two JWK, one with kid="1" and another with kid="2". If your JWT has a field like "kid" : "1" or "kid" : "2", then Apigee will find the appropriate JWK. If your JWT does not have a kid field in the header or the value of the kid field in the header does not match one of the kids in the JWKS, then you will see the error "Could not find a matching Public Key". This is as expected and desired. We do not want to verify JWT that have been signed with unknown keys.

To understand what kid is in the header, you can paste your JWT into an online decoder, like this one. Results will be like so:

screenshot-20230512-081759.png

As you can see in this case the kid field in the decoded header holds "abcdefg". 

Hello,

Thanks for the response.

In the Trace files, we can see that the header value is Kid 2 (as attached in the snapshot) , and it is still not able to refer the certificate of kid 2 and throws error given below

Could not find a matching Public Key 

 

 

suma_1-1684131885871.png

Also we tried sending only 1st array value from the Url into a flow variable and sending the variable in the public key . This also throws the same error .please refer below :

suma_2-1684132114435.png

in the abobe policy there is base64 encoded value for ==. We have tried sending both \u003d and == in the value but same error .

suma_3-1684132148540.png

Request you to help us solve the issue . 

Thanks,

Suma

 

 

 

So it is not a problem with the kid value. 

Ah, I think I see the problem. I Think the Apigee policy will select a key only if the entry has an n and e property. the Apigee policy will not resolve a key if the key is specified as x5c or x5u. This is a limitation of the Apigee policy. If you can get your JWKS into a form that publishes n and e , rather than , or in addition to x5c, then the key selection should work the way you want it to.  

   {"keys":
       [{
         "kty":"RSA",
         "kid":"no-good--will-not-be-selected-by-Apigee",
         "x5c":
          ["MIIDQjCCAiqgAwIBAgIGATz/FuLiMA0GCSqGSIb3D...vdXK3IVfOWA=="]
        },
        {
         "kty":"RSA",
         "kid":"good-this-will-work",
         "n": "0vx7agoebGcQSuuPi...JzKnqDKgw",
         "e":"AQAB"
        }
       ]
     }

 

Thanks for the details. We noticed that n and e were missing from the certificate endpoint but we were not sure if they are mandatory attributes to be included in Apigee policy. We will check with our internal team exposing these details . 

Good observation @dchiesa1 .

@suma :  Can you check the JSON structure that is returned as part of the JWKS endpoint call? Do not construct the JSON structure at your own will, as this will never work. You need to understand each attribute before attempting to do so.

For good reference go thru the spec and understand the what JWKS https://datatracker.ietf.org/doc/html/rfc7517

Apigee document reference:

 

 

Hello,

Yes we did check and we were not sure of n and e to be present as part of policy. We'll check internally for these attributes . 

 

 

Thanks

Suma

It is pretty straightforward to derive an n and e parameter from an x5c.  So if absolutely necessary, you could ... insert an Apigee proxy in front of your JWKS endpoint, and do that transformation dynamically.  Then specify the jwks-proxy URL, rather than the actual JWKS endpoint, in your VerifyJWT policy. 

The jwks-proxy should, in the response flow,

  • iterate through each JWK
  • for each one that has an x5c but does not have {n,e}
  • de-serialize the x5c value into an X509 certificate
  • extract the public key from the certificate
  • get the modulus and the exponent from the public key
  • base64 encode each and insert those as {n,e} into the JWK
  • re-serialize the JWK

This would best be done in a Java callout. 

But the ideal approach would be for the JWKS endpoint to just publish {n,e} directly. 

 

You can try using this Java callout to transform your JWKS:

https://github.com/DinoChiesa/Apigee-Java-Transform-Jwks

Hi @dchiesa1 ,

Thanks for the API Bundle. We will try from our end will update the status

Regards,

Suma