Unable to create JWT using third party JWKS

Hi,

I am getting the below problem while generating JWT with JWKS.

Steps to create JWT with JWKS

Step-1Generate JWKS using a third-party tool (https://mkjwk.org/)

Step-2Configure step-1 key in KVM

{
    "keys": [
        {
            "kty": "EC",
            "d": "7MJbpdnCfFODZApvMpjgtVrJsePt2_y-_D3wUkzlUvA",
            "use": "enc",
            "crv": "P-256",
            "kid": "demoid",
            "x": "qQy5GfBw9l3ArH-zH61gXtzTDmGZqjN6dAb-8IFpRE4",
            "y": "hm1rHBR4vwfJo8W2bH7Um_ui5UAfWj_1UbiMJPd7RlQ",
            "alg": "ES256"
        }
    ]
}

Step-3: Using below Policy

<GenerateJWT async="false" continueOnError="false" enabled="true" name="Generate-Guest-JWT-RSA">
    <DisplayName>Generate Guest JWT-RSA</DisplayName>
    <!-- specify the key and content algorithms -->
    <Algorithms>
        <Key>ECDH-ES+A256KW</Key>
        <Content>A128GCM</Content>
    </Algorithms>
    <!-- specify the public key to use for encryption -->
    <PublicKey>
        <JWKS ref="rsa.JWTKey"/>
        <!--<Value ref="rsa_publickey"/>-->
    </PublicKey>
    <!-- any additional configuration elements you like -->
    <Subject>application-access</Subject>
    <Issuer>urn://apigee-edge-JWT-policy-test</Issuer>
    <Audience>guest</Audience>
    <ExpiresIn>30m</ExpiresIn>
    <OutputVariable>jwt-variable</OutputVariable>
</GenerateJWT>

Step-4: Getting below error with response status code 500

{
    "fault": {
        "faultstring": "Could not find a matching Public Key: policy(Generate-Guest-JWT-RSA)",
        "detail": {
            "errorcode": "steps.jwt.NoMatchingPublicKey"
        }
    }
}

I am using "Apigee Edge free trial" i.e. javaCallout is disabled.

Does Apigee support third-party JWKS? if so, what are the criteria to choose/select an appropriate algorithm for the above (step-2) keys?

I am using JWKS based on https://community.apigee.com/questions/86298/encrypting-jwt-using-jwks.html. Is there any appropriate documentation?

<PublicKey> <JWKS ref="private.key"/> <Id>csrfJwtEncryptionKey</Id> </PublicKey>

Here are reference links but couldn't get any clue yet. Algorithm:

  • https://community.apigee.com/articles/86125/generating-and-verifying-encrypted-jwt-in-apigee.html
  • Idon't want to useNodejs to generate JWKS e.g. Nodejs : https://community.apigee.com/questions/67537/publish-and-generate-jwks.html andhttps://github.com/DinoChiesa/Apigee-JWT-with-JWKS
  • Solved Solved
    1 12 1,541
    1 ACCEPTED SOLUTION

    OK, lots going on here. Let me try to help.

    If you are using GenerateJWT to generate an encrypted JWT, you must specify both the key-encrypting-algorithm and the content-encrypting-algorithm .

    I'm sorry, I had not looked at your earlier configuration very closely. The key encrypting algorithm you specified was ECDH-ES+A256KW:

       <Algorithms>
            <Key>ECDH-ES+A256KW</Key>
            <Content>A128GCM</Content>
        </Algorithms>
    

    The algorithm is described in RFC 7518, JWA. To use this algorithm you must specify an elliptic curve key. You cannot use an RSA key with an algorithm in the ECDH-ES family.

    If you wish to use an RSA Public key to drive the encryption, then you. need to use an algorithm that relies on RSA public keys. In other words, one of the following:

    • RSA-OAEP
    • RSA-OAEP-256
    • RSAES-PKCS1-v1_5

    At the time the policy executed, the problem it encountered is that the algorithm you specified is not compatible with the key obtained from the key-source you provided (the JWKS). This is the meaning of the error message you see, "Could not find a matching Public Key".

    Regarding "RSA key is managed in KVM" .... I think that is not relevant. The place you have stored your key is not affecting the behavior you are reporting.

    After looking further, I think I may have confused myself. Your variable is named "rsa.JWTKey" but it does not contain an RSA Key. In fact it contains a JWKS. And you are not trying to perform RSA encryption - it appears you are trying to perform EC encryption using an EC key, which all seems to be appropriate.

    Can you try this? Try to modify your JWKS so that it omits either or both of "use" and "alg". So that it looks like this:

     {
        "keys": [
            {
                "kty": "EC",
                "d": "7MJbpdnCfFODZApvMpjgtVrJsePt2_y-_D3wUkzlUvA",
                "crv": "P-256",
                "kid": "demoid",
                "x": "qQy5GfBw9l3ArH-zH61gXtzTDmGZqjN6dAb-8IFpRE4",
                "y": "hm1rHBR4vwfJo8W2bH7Um_ui5UAfWj_1UbiMJPd7RlQ"
            }
        ]
    }

    View solution in original post

    12 REPLIES 12

    If you provide a JWKS with exactly one key, the GenerateJWT policy will not be smart enough to select that key. Instead, it uses a kid as discriminator. You can do something like this:

      <PublicKey>
        <JWKS ref='jwks_json'/>
        <Id>demoid</Id>
      </PublicKey>
    

    It is not working. Do I need to configure the appropriate Algorithm type?

    I am referring to your community site

    https://community.apigee.com/articles/86125/generating-and-verifying-encrypted-jwt-in-apigee.html

        <!-- specify the key and content algorithms -->
        <Algorithms>
            <Key>ECDH-ES+A256KW</Key>
            <Content>A128GCM</Content>
        </Algorithms><br>

    Below is the Policies screenshots

    generatejwt-jwks.png

    10714-generatejwt-jwks.png

    OK, lots going on here. Let me try to help.

    If you are using GenerateJWT to generate an encrypted JWT, you must specify both the key-encrypting-algorithm and the content-encrypting-algorithm .

    I'm sorry, I had not looked at your earlier configuration very closely. The key encrypting algorithm you specified was ECDH-ES+A256KW:

       <Algorithms>
            <Key>ECDH-ES+A256KW</Key>
            <Content>A128GCM</Content>
        </Algorithms>
    

    The algorithm is described in RFC 7518, JWA. To use this algorithm you must specify an elliptic curve key. You cannot use an RSA key with an algorithm in the ECDH-ES family.

    If you wish to use an RSA Public key to drive the encryption, then you. need to use an algorithm that relies on RSA public keys. In other words, one of the following:

    • RSA-OAEP
    • RSA-OAEP-256
    • RSAES-PKCS1-v1_5

    At the time the policy executed, the problem it encountered is that the algorithm you specified is not compatible with the key obtained from the key-source you provided (the JWKS). This is the meaning of the error message you see, "Could not find a matching Public Key".

    Regarding "RSA key is managed in KVM" .... I think that is not relevant. The place you have stored your key is not affecting the behavior you are reporting.

    After looking further, I think I may have confused myself. Your variable is named "rsa.JWTKey" but it does not contain an RSA Key. In fact it contains a JWKS. And you are not trying to perform RSA encryption - it appears you are trying to perform EC encryption using an EC key, which all seems to be appropriate.

    Can you try this? Try to modify your JWKS so that it omits either or both of "use" and "alg". So that it looks like this:

     {
        "keys": [
            {
                "kty": "EC",
                "d": "7MJbpdnCfFODZApvMpjgtVrJsePt2_y-_D3wUkzlUvA",
                "crv": "P-256",
                "kid": "demoid",
                "x": "qQy5GfBw9l3ArH-zH61gXtzTDmGZqjN6dAb-8IFpRE4",
                "y": "hm1rHBR4vwfJo8W2bH7Um_ui5UAfWj_1UbiMJPd7RlQ"
            }
        ]
    }

    Thank you Dino, it is working as per your suggestion. I agree with you that the incorrect variable name in my code but stores JWKS is in my KVM as you can see in screenshots.

    'use' and 'alg' parameters are supported in RFC7517. Is it a known issue in Apigee to use such parameters?

    10715-rfc7517.png

    Yes, the policy does examine the use and alg properties. That is the problem.

    Apigee is trying to strictly respect the "use" and "alg" properties.

    The Algorithm you are specifying in the encryption is "ECDH-ES+A256KW". That is an encryption alg. The alg specified in the JWK reads "ES256". This mismatch is causing Apigee to refuse to select the key.

    If you tried to use your original JWK with a GenerateJWT for a Signing operation, using ES256 as the algorithm in the policy configuration, then the "alg" property on the JWK will find a match. But the "use" property in your JWK is "enc" . Selecting that key for signing, Apigee looks for a "use" : "sig", which means that still may cause a mismatch.

    It might be better for Apigee to simply ignore those properties. That would eliminate frustration for people like yourself. I am uncertain whether that would represent a security vulnerability. It does seem to me that "use" and "alg" are there for a good reason. For good hygiene, if there is a "use" and an "alg" on a JWK, the consumer of the JWK (in this case Apigee) should respect those properties. But I understand it's frustrating.

    We may change the behavior; need to consider this. For now, you can avoid the restrictive behavior by simply removing the "use" and "alg" properties on the JWK.

    Hey Dino, I saw your utility for JWKS with algorithm RSA256 (https://github.com/DinoChiesa/Apigee-JWT-with-JWKS)

    It's a nice utility. Do we have any utility for encryption algorithm used in JWKS? e.g. JWKS will have attributes likes ("kty": "EC","use": "enc","crv": "P-256","alg": "ES256" )

    I'm not sure; I think the solution may be simply to remove the "use" and "alg" properties, and it should just work. Will that satisfy?

    Thank you Dino for your quick response. It is working fine after removing "use" and "alg".

    Now I am trying to create JWT with JWKS using Apigee Policies

    1. Category-1: JWE of RSA type [Able to generate after going through your approach e.g. Key encryption: RSA-OAEP-256, Content encryption: A128GCM]
    2. Category-2: JWE of EC type [Need your inputs]

    Below queries are related to Category-2

    Is there any Apigee example/reference to generate JWT with EC key pair?

    or

    Could you please let me know changes that need to be configured in provisionNewKeyPair.js to generate EC

    Tattwadarsi, let me look . I think I can expand the example to show generation of an EC key.

    EDIT : ok, I've updated the provisionNewKeyPair.js tool to create an EC key as well. Does this help?

    If you just want a JWKS service.... for development and testing purposes, you can use this: https://jwks-service.appspot.com/

    Thnank you Dino, I don't see any update in provisionNewKeyPair.js (https://github.com/DinoChiesa/Apigee-JWT-with-JWKS/blob/master/tools/provisionNewKeyPair.js).

    Is it the same file or a new file?

    I'm sorry Tattwa, I had forgotten to "git push". The update should be there now. Please check again.

    You will need to "git pull". I've updated that script, but also refactored things a little. That script depends on a new library, where I've moved logic that was re-used across all three of the scripts.

    So you cannot simply download that one new script. "git pull" should set you right.

    Thank you so much Dino for your quick help. Now, it is working for me.