JWT Policies in Apigee Edge

Hey there, Apigee Community friends!

Time for another video. This one is a bit longer, and covers the new JWT policies that are available in Apigee Edge. YES! Apigee Edge now has builtin policies that can generate or verify JWT, according to your configuration. Here’s a sample configuration for VerifyJWT:

<VerifyJWT name="Verify-JWT-1">
    <Algorithm>RS256</Algorithm>
    <Source>inbound.jwt</Source>
    <PublicKey>
        <Value ref='publickey'/>
    </PublicKey>
    <Audience>urn://Apigee</Audience>
</VerifyJWT>

And here is a sample policy configuration for Generating a JWT:

<GenerateJWT name="Generate-JWT-1">
    <Algorithm>RS256</Algorithm>
    <PrivateKey>
        <Value ref="private.privatekey"/>
    </PrivateKey>
    <Subject ref="request.formparam.subject"/>
    <Issuer>urn://apigee-edge-JWT-policy-demonstration</Issuer>
    <Audience ref="request.formparam.audience"/>
    <ExpiresIn>60m</ExpiresIn>
    <OutputVariable>output-jwt</OutputVariable>
</GenerateJWT>

I’ve just reprised this Screencast to provide some additional information. I hope you’ll click and enjoy.

Click to view the screencast . BTW, the source-code accompanying the screencast is available on Github.

FAQ

Q. How does this new set of policies differ from the Java callout that has been available for some time?

A. The new policies are a supported part of the Apigee Edge product. They’ll be built, tested, and maintained by Apigee engineers according to the product standards. There is official documentation and support for these policies.

The Java callout is an open-source project, and is not part of the supported Apigee Edge product. There’s no official documentation and support was done through a volunteer, best-effort basis. Since there is no way to add a custom policy into the user interface, the Java callout could never appear in the policy-selector UI.

JWT of course is an open standard, and there’s nothing technically wrong with using your own custom code to parse or generate JWT. But we think there are advantages in the developer experience with delivering a supported policy.

Q. I’ve been using that Java callout for some time, it works great. Should I convert to using this builtin policy?

Probably. The Java callout works just fine, but we think the new builtin policies will be more efficient, especially at scale. They’ll also be easier to maintain, with better documentation and support.

Converting from the Java callout configuration to the config for one of the builtin policies will be basically mechanical. Renaming elements and so on. It will be a low-effort affair. You should be able to convert a policy in about 60-90 seconds.

Q. I’ve been doing JWT in a nodejs target for some time, it works great. Should I convert to using this builtin policy?

Probably. You may be depending on one of the various nodejs libraries for JWT, like jsonwebtoken, or node-jwt. The nodejs target in Apigee Edge is based on Trireme, which is a JavaScript interpreter that itself runs inside the JVM. The cpu efficiency of JS code running on top of that stack is poor, compared to directly compiled Java code. This matters especially with RSA algorithms, but it also has an effect on HMAC algorithms. If you have high load, you will want to use the more efficient option, and that’s the built-in policy types.

Q. Do the JWT policies enforce any particular format on the JWT they generate or verify?

No. Apigee Edge can verify JWT generated by Azure, Google Signin, Salesforce, Ping, Paypal, or other systems. When generating a JWT, you can embed payload claims of any type into the token. Also, Apigee Edge can generate JWT that can be verified by any other system.

Q. Will the VerifyJWT policy directly implement RFC7523?

No, but you can implement RFC7523 grants in your API Proxy. Consult the prior article describing the technique; all you need to do is replace the Java callout in that example with the builtin Apigee Edge policy.

Q. Will Apigee Edge provide more support for OpenID Connect?

OpenID Connect wraps user authentication around the OAuth 2.0 three-legged protocol. There is a prior community article discussing OpenID Connect and Apigee Edge. The basics of that article still apply, now that there is a builtin GenerateJWT policy.

Apigee is investigating deeper support for OpenID Connect, but we have nothing to announce at this time.

Q. I see the policy supports RSA and HMAC signing. When will other algorithms be supported, like ECDSA?

ECDSA is on the roadmap, but we don’t have a firm schedule for this. Soon! Expected Summer 2018.

Q. What about encrypted tokens, JWE? Will Apigee support that with a builtin policy?

We have no immediate plans to ship a policy that does JWE, but we are always interested in customer requirements. For now you may have to rely on custom Java code for this technical use case.

Q. I’d like to verify JWT using certificates stored in the Apigee truststore. But there is no way for the API Proxy to directly read from the truststore. Will Apigee allow this in the future?

We are investigating that possibility. Right now we don’t view this limitation as severe, as there is a pretty simple workaround: load the certs and keys into the KVM.

Q. Why does Apigee force me to use a private. variable for configuring Private keys or secret keys in the JWT policy configuration?

We are encouraging good security practices by enforcing the use of a private variable. You cannot key in secrets like passwords or PEMs for private keys into the policy configuration files. We feel the right place for this information is in a secure store, such as the Encrypted KVM which is part of Apigee Edge. Of course you can embed public keys directly into the policy configuration, if you wish. Public keys aren’t secrets!

Q. OK, I see the merit in that. How do I load my privatekey.pem file into the KVM?

You should do it via the administrative API. Today the Admin UI does not handle newlines very well. (bug ref b/64808634 ) There’s a bash script available here that can help. Or if you prefer nodejs, check here. I haven’t created an example for Powershell, let me know if you want one. The key point: You need to be careful escaping newlines.

8 Likes

Just what the doctor ordered, wonderful and thank you

Great news. Any idea when is it expected ? We are eagerly waiting for this.

Good news. How do we get those new policies on to the existing on-prem Apigee instance?

1 Like

These policies will roll to OPDK in a future release. We haven’t announced specifically. 18.01 would be the next logical candidate. You will need to upgrade your installation in order to get them.

UPDATE: Yes, the JWT policies are available in 18.01

These policies are available as Alpha in Edge SaaS. You can request enablement from Apigee Support. Current plan is to make them generally available to everyone in January.

Thanks @Dino,

We got it in our orgs. One query: when I am trying to assign an array to our custom claims, the decoded jwt has “/”, like

"software_redirect_uris": "[\"https://prime.amazon.com/cb\"]"<br>

Although the in the previous java script policy and in the JWT generate policy, we are able to see proper value:

redirectUrisArray ["https//prime.amazon.com/cb"]

Any pointer on this ?

Thank you. Does it support kid?

Yes.

  • On Generation, of course you can configure the policy to embed a kid claim in the JWT header. And that claim can hold any value.
  • On Verification (probably what you were asking about), you can specify a JWKS. If the JWT to be verified contains a kid in the header, the JWT policy will extract the appropriate key from the JWKS based on the kid, and will verify the JWT as appropriate.

Does this answer your question?

Yes - there is a way in the JWT Alpha to specify that your custom claim (software_redirect_uris) should contain an array. You need to use type=‘string’ and array=‘true’. We are working to make this simpler in the general release, so that the policy “does the right thing”, basically a JSON.parse() of the value used for the claim.

I just cannot find where I can configure jwt headers in GenerateJWT policy.

Ah yes, it is not possible to do that using the Alpha policy. This is a feature people have asked for. We have added it to the policy, and it will be possible when we release in January.

EDIT - this is available now. Use the AdditionalHeaders element. Example:

<GenerateJWT name="Generate-JWT-RS256-AdditionalClaims">
    <Algorithm>RS256</Algorithm>
    <PrivateKey>
        <Value ref="private.privatekey"/>
        <Id>unique-identifier-for-privatekey-here</Id>
    </PrivateKey>
    <Id/> <!-- generate a unique identifier -->
    <AdditionalHeaders>
      <Claim name='whatever' ref='apiproxy.name'/>
    </AdditionalHeaders>
    <Subject ref="request.formparam.subject"/>
    <Issuer>urn://apigee-edge-JWT-policy-demonstration</Issuer>
    <Audience ref="request.formparam.audience"/>
    <ExpiresIn>10m</ExpiresIn>
    <AdditionalClaims>
      <Claim name='apigee-proxy' ref='apiproxy.name'/>
      <Claim name='messageid' ref='messageid'/>
      <Claim name='request-path' ref='request.path'/>
      <Claim name='apigee-org' ref='organization.name'/>
      <Claim name='apigee-env' ref='environment.name'/>
    </AdditionalClaims>
    <OutputVariable>output-jwt</OutputVariable>
</GenerateJWT>

How do I specify modulus and exponent in the VerifyJWT Policy instead of Public Key? There was a way to do that in the callout. Just looking for the format to specify.

Do it with the JWKS. You need the modulus and exponent wrapped in a JWKS, and then the JWT-to-be-verified must refer to the kid.

There is no way to directly specify the modulus and exponent.

Thanks Dino. I should have watched your video until the end :).

Hey Dino, I was trying to validate the jwt generated from apigee edge in Azure Functions and I found out that when you assign the value of private key in the PEM format, you need to remove the BEGIN PRIVATE KEY and END PRIVATE KEY related lines from the file. If you don’t do that, GenerateJWT policy seems to work without any problems but the signature cannot be validated. I am hoping that this will save time for somebody else.

Has anyone else seen this behavior :

From time to time the ‘Decode JWT’ policy sets the variable name suffix to unexpected values. For example, I have seen jwt.xxx.custom_claims.scp and jwt.xxx.claims.scp used. I’m looking for the values of these variables, so when the name changes my ‘Raise Value’ conditions get all messed up.

I know that this policy is in ‘Beta’, so I understand that this may just be a development bug. Does anyone have thoughts and/or comments?

Thank you for the examples! The have been quite helpful. I noticed that when running the examples that I wasn’t getting some of the values from the inbound JWT token into the outbound token.

For some reason, I had to add “.claim” in SOME of the variables. I assume there’s a reason for it and it’s beta, but may want to update the examples? Not sure, but sharing all the same.

{ “status” : “ok”, “algorithm” : “{jwt.Verify-JWT-2.claim.algorithm}”,

“claim_names” : “{jwt.Verify-JWT-2.payload-claim-names}”,

“subject” : “{jwt.Verify-JWT-2.claim.subject}”,

“issuer” : “{jwt.Verify-JWT-2.claim.issuer}”,

“audience” : “{jwt.Verify-JWT-2.claim.audience}”,

“expiry” : “{jwt.Verify-JWT-2.expiry_formatted}”,

“seconds_remaining” : {jwt.Verify-JWT-2.seconds_remaining},

“out.now” : “{outbound.now}” }

when there will be a tutorial step by step for dummies in the Apigee Docs?

Hi @Rafael Obara, for step by step tutorial, follow below Github project by Dino,

https://github.com/DinoChiesa/ApigeeEdge-JWT-Demonstration