Hello @dchiesa1
I am migrating a proxy from Apigee Edge to Apigee X. This proxy includes a managed hosted resource and a Node.js server running in Apigee Edge. When other proxies forward requests to this endpoint, the Node.js module (a JavaScript file) modifies the message and uses the JWKS client to send a request to Google API OAuth v3 for retrieving the public key, which is then returned to the requesting proxies.
jwks_client.getSigningKeyAsync(kid, (err, key) => {
const signingKey = key.getPublicKey();
res.end( signingKey );
});
My proxy default.xml look like this
<HTTPProxyConnection>
<BasePath>/jwks-rsa</BasePath>
<VirtualHost>secure</VirtualHost>
<VirtualHost>secure-apigee</VirtualHost>
<VirtualHost>secure-apigee-temp</VirtualHost>
</HTTPProxyConnection>
Are there any ways to send the jwks-client request within the proxy itself?
Thanks
Kevin
Solved! Go to Solution.
Maybe?
You're asking me if it's possible to retrieve a specific key from a JWKS, within Apigee, without resorting to the nodejs logic that wraps the Google OAuth library (I think).
The JWKS endpoint for Google is here: https://www.googleapis.com/oauth2/v3/certs . If you are using Firebase Auth, there's a different JWKS endpoint.
You can use a serviceCallout to retrieve that payload. It's a JSON.
<ServiceCallout name='SC-Get-Google-JWKS'>
<Request variable='simpleGetRequest'>
<Set>
<Verb>GET</Verb>
</Set>
</Request>
<Response>jwksResponse</Response>
<HTTPTargetConnection>
<SSLInfo>
<Enabled>true</Enabled>
<IgnoreValidationErrors>false</IgnoreValidationErrors>
</SSLInfo>
<Properties>
<Property name='success.codes'>2xx</Property>
</Properties>
<URL>https://www.googleapis.com/oauth2/v3/certs</URL>
</HTTPTargetConnection>
</ServiceCallout>
You can then use Jsonpath to retrieve a specific key , by key id (kid).
<AssignMessage name='AM-Extract-JWK-via-Jsonpath'>
<AssignVariable>
<Name>json_path_1</Name>
<Template>$.keys[?(@.kid == '{request.queryparam.desiredkid}')]</Template>
</AssignVariable>
<AssignVariable>
<Name>jwk</Name>
<Value>BADDBEEF</Value>
<Template>{jsonPath(json_path_1,jwksResponse.content)}</Template>
</AssignVariable>
</AssignMessage>
Then you have a JWK. What do you want to do with that JWK? What's the real goal?
Usually you use the JWK to verify the signature on a signed JWT, or to encrypt data in an encrypted JWT. And, you have builtin Apigee policies that can do those things, and if you use them, you don't have to worry about retrieving the specific key by key-id. The policies do that for you.
What I mean is, suppose you have a signed JWT with kid=abc123. If it was signed by google, then you can just use the VerifyJWT policy, specify the PublicKey source as that URL ^^ I cited above, and the policy will examine the JWT, find the kid, retrieve the JWKS, extract the key with that kid, then verify the signature on the JWT. It does all that for you, and you don't need to worry about the mechanics of retrieving a specific key.
Having said that, I suppose there might be cases where you'd want the specific JWK structure. Right now I am not thinking of any mainstream cases, but I suppose it's possible. And if you have such cases, then I suggest ServiceCallout + AssignMessage with a jsonpath, as I showed above.
Is there a way to convert the JSON format to PEM format inside the proxy?
Maybe this? https://github.com/DinoChiesa/Apigee-Java-Transform-Jwks
The ServiceCallout + AssignMessage method supports only one target backend service. Do you have any suggestions for enabling this method to work with more than one target backend service?
I don't really understand that. You can set dynamic URLs for servicecallout. Search on this community for hints.