Failed to parse key: policy(Verify-JWT-Token) when reading from variable

Hi

I am retrieving public key from URL (https://<host>/v2/common/jwks.json) via service callout policy then storing response in variable "publicKey". Since URL for public key will be different for different environment, I thought of using this URL from KVM for my service callout policy and extracting public key and putting in variable "publicKey". Here everything works fine. Now I simply want to pass reference of this variable to <JWKS ref="publicKey"/> below. but it gives  

Failed to parse key: policy(Verify-JWT-Token) when reading from variable

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<VerifyJWT async="false" continueOnError="false" enabled="true" name="Verify-JWT-Token">
<DisplayName>Verify JWT-Token</DisplayName>
<Algorithm>RS256</Algorithm>
<Source>oauthtoken</Source>
<PublicKey>
<JWKS ref="publicKey"/> 
</PublicKey>

My Goal is, I want to read JWKS dynamically. 

When I use <JWKS uri="https://<host>/v2/common/jwks.json"/> it works fine. But this URL will be different for different environment. Another issue is I cant use variable with  <JWKS uri="variable"/> - It does not support variable and give error on Save

0 2 308
2 REPLIES 2

Have you performed a debug/trace of your API proxy to check and confirm the value of the publicKey variable before it's used by the VerifyJWT policy?

Ya, I think you will succeed if you use the correct syntax. Here are the options

 

  <PublicKey>
    <!-- 1. you have a variable that contains a JWKS, a JSON payload desribing keys -->
    <JWKS ref='jwksResponse.content'/>
    <!-- 2. you have a specific, static URL at which the JWKS can be retrieved -->
    <JWKS uri='https://hardcoded.uri.here/jwks.json'/>
    <!-- 3. you have a variable containing a URL at which the JWKS can be retrieved -->
    <JWKS uriRef='variable-containing-jwks-uri'/>
  </PublicKey>

 

These options are described in the documentation for VerifyJWT.

So what you want is probably something like

 

<VerifyJWT name="Verify-JWT-Token">
  <Algorithm>RS256</Algorithm>
  <Source>oauthtoken</Source>
  <PublicKey>
    <JWKS uriRef="variable-containing-a-jwks-uri"/> 
  </PublicKey>
</VerifyJWT>

 

The variable can be set in any way you want. One possibility is to set the various options in a properties file, attached to the API Proxy, that contains all of the URIs for all of the environments.  If you do this, you can then use AssignMessage to resolve the correct URI for the environment in which the API Proxy is executing. For example you can have a settings.properties file like this in your proxy:

 

# These are the various JWKS URIs. They each have the environment name as suffix.
jwks_uri_dev = https://jwks-uri-for-dev/.well-known/v1/keys
jwks_uri_prod = https://jwks-uri-for-prod/.well-known/v1/keys

# This will be treated as a MessageTemplate in an AssignMessage policy,
# to return the NAME of one of the above.
jwks_endpoint_variablename_tmpl = propertyset.settings.jwks_uri_{environment.name}

 

And then an AssignMessage like this:

 

<AssignMessage name='AM-Resolve-JWKS'>
  <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>

  <!--
      The following uses the string stored in
      propertyset.settings.jwks_endpoint_variablename_tmpl
      as a _template_. Apigee will resolve the variable references
      contained within it, to fill the named variable, jwks_endpoint_variable.
  -->
  <AssignVariable>
    <Name>jwks_endpoint_variable</Name>
    <Template ref='propertyset.settings.jwks_endpoint_variablename_tmpl'/>
  </AssignVariable>

  <!--
      This creates a new template. Using double curlies surrounds
      in the template resolves to a pair of single curlies around
      the named variable.
  -->
  <AssignVariable>
    <Name>tmpl2</Name>
    <Template>{{jwks_endpoint_variable}}</Template>
  </AssignVariable>

  <!--
      Finally, get the URI value into jwks_endpoint.
  -->
  <AssignVariable>
    <Name>jwks_endpoint</Name>
    <Template ref='tmpl2'/>
  </AssignVariable>
</AssignMessage>

And then reference that in your VerifyJWT policy with the uriRef attribute.

<VerifyJWT name="Verify-JWT-Token">
  ...
  <PublicKey>
    <JWKS uriRef="jwks_endpoint"/> 
  </PublicKey>
  ...

Another way to do it is to use a distinct properties file attached to each environment.  You need to use the Apigee API to attach these properties files to the environment.

# Do this for each environment
POST :gaambo/v1/organizations/:org/environments/:env/resourcefiles?type=properties&name=settings
Authorization: Bearer :token
Content-Type: application/octet-stream

jwks_endpoint = https://uri-for-dev/.well-known/jwks.json

If you do it this way, there's less fiddling around in the proxy with the AssignMessage to resolve it.  You would just refer directly to propertyset.settings.jwks_endpoint in the policy: 

<VerifyJWT name="Verify-JWT-Token">
  ...
  <PublicKey>
    <JWKS uriRef="propertyset.settings.jwks_endpoint"/> 
  </PublicKey>
  ...