How do configure APIGEE to use JWT Tokens for Google Healthcare API?

I followed the steps here https://cloud.google.com/architecture/using-apigee-with-the-cloud-healthcare-api to setup apigee with google healthcare api. However I would like it to use JWT Tokens for SMART so i replaced the OAuth api policy to 

 

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OAuthV2 continueOnError="false" enabled="true" name="OAuth-v20">
    <!-- This policy generates an OAuth 2.0 access token using the client_credentials grant type -->
    <Operation>GenerateJWTAccessToken</Operation>
    <Algorithm>HS512</Algorithm>
    <SecretKey>
        <Value ref="private.mysecretkey"/>
    </SecretKey>
    <!-- This is in milliseconds, so expire in an hour -->
    <ExpiresIn>3600000</ExpiresIn>
    <SupportedGrantTypes>
        <GrantType>client_credentials</GrantType>
    </SupportedGrantTypes>
    <GrantType>request.queryparam.grant_type</GrantType>
    <GenerateResponse/>
</OAuthV2>

 

 

and I'm currently getting this error. "Provided Key required for signing the token is unresolvable". Can anyone help me with the missing steps?

2 6 267
6 REPLIES 6

Do you have a secretkey value stored in

private.mysecretkey

?  If you want Apigee to sign a JWT, you need to provide a key.  And it looks like it the policy can't resolve that variable, into a key.

For HS512, I think there is a minimum key size of 64 bytes... It could be that you've provided a key that is insufficient?  But I am not sure about that.

The command i used to call in curl is 

curl -X POST https://{api-domain-name}/oauth2/token?grant_type=client_credentials -H "Authorization: Basic {base64string}"

where the base64string is encoded using key:secret found in the APIGEE Apps tab of my api. Should i put the key in private.mysecretkey? or do I need to generate one? I'm not familiar with implementation of JWT on APIGee 

When you use OAuthV2/GenerateJWTAccessToken, with the HS512 algorithm, You need to use SOMETHING as the secret key. HS512 is going to require a key of at least 64 bytes.

When you create an App registration in Apigee, Apigee generates a {key,secret} pair. The secret is 64 bytes in length. So you could use that secret value as the key for signing the JWT with HS512. You could use "private.mysecretkey" in the policy configuration, or some other variable name.  The name of the variable doesn't actually matter.  The important thing is the value the variable holds.  Whatever name you use, you need to load a value of 64 bytes into that variable. 

To use the client secret as the secret key, you must first extract that secret from the base64-encoded blob that gets passed in the Authorization header. The header will look like this:

Basic NTZuQVFHT1lvU2pUWmkzb1d...lots..of...characters....m05OUxSdzl1MElLd04xV1Y2HTUhRb3RIeG0=

And you can use the BasicAuthentication policy in Apigee to extract the constituent parts from that encoded blob.  That will retrieve the client_id and client_secret, and at that point you could call OAuthV2/GenerateJWTAccessToken , specifying the extracted client_secret as the variable that holds the SecretKey value. (Again, which variable name you use for SecretKey in theOAuthV2/GenerateJWTAccessToken  policy, depends on how you configured the BasicAuthentication policy - in other words, which variable you told the BasicAuthentication policy to load with the decoded secret value. )

But, more importantly...

WHY are you doing this?  What are you solving for here? Your title said something about "JWT Tokens for Google Healthcare API".  What does OauthV2/GenerateJWTAccessToken have to do with tokens for the Google Healthcare API? 

When you use OAuthV2/GenerateJWTAccessToken with HS512, you're generating a token that can be used by Apigee, or by any system that "knows" the secret key.  I don't think the Google Healthcare API can use that token.  

If by "Healthcare API", you are talking about the thing you can reach at healthcare.googleapis.com , then you need to pass an access token with such requests.  A token you create with the Apigee policy OAuthV2/GenerateJWTAccessToken is not the right kind of token.  I think in general the healthcare API expects access tokens that look like any other access token for Google cloud, which means it is an access token that has been be generated by the Google OAuth2 endpoints. 

I summarized some things regarding access tokens for google properties (like healthcare.googleapis.com) here: https://github.com/DinoChiesa/get-gcp-access-token   How to get them, how they work, etc.

 

You started by asking about a specific policy configuration in Apigee. If you take a step back and explain the entire system, and your broader goals, someone here might be able to provide more helpful advice.  Including advice on whether you even need that policy. 

Right, to explain what i'm trying to solve, basically I followed the steps here https://cloud.google.com/architecture/using-apigee-with-the-cloud-healthcare-api to use APIGEE X with google healthcare api. 

I'm currently trying to implement SMART on FHIR and it requires an authorization server that mints SMART JWT Tokens thus i'm trying to modify apigee to use GenerateJWTAccessToken. Am i on the right track here?

I looked through that page and I don't see anything related to GenerateJWTAccessToken. 


@ray1234 wrote:

it requires an authorization server that mints SMART JWT Tokens


Where is this stated? Are you talking about section 4.1.5.1 here?  The one that uses a grant_type = urn:ietf:params:oauth:grant-type:jwt-bearer ?  My understanding, from reading that, is that the CLIENT needs to generate a one-time use JWT, and send it to the authorization server, when it requests an access token.  The client, in this case (if I understand correctly) is not Apigee.  Apigee acts as the authorization server, I think. Therefore you cannot use the Apigee policy OauthV2/GenerateJWTAccessToken.  Apigee will receive the JWT that is generated by the client.  So you need some kind of code on the client, that can generate that JWT, and that code is not an Apigee policy. 

That document also states that the one-time use JWT "SHALL be signed with the client’s private key (which SHOULD be an RS384 or ES384 signature)."  You're doing HS512, which means , if I understand correctly, it's wrong in 2 ways.  (1) you're using Apigee to generate the JWT, when it should be the client, and (2) you're not using the right algorithm.

This seems like an example  that would be applicable, to show how Apigee can RESPOND to a request for access token, when the client sends in a JWT.  The code that generates the JWT on the client side, in that example, is a bash script, which wraps a Java program!  

I'll work on producing a screencast covering this.

In the meantime, (this is going to sound cliche, but I'll say it anyway ...) My suggestion is to break-down what you're trying to do, into parts, and just solve for each part. 

 

EDIT: Here's an example repo that shows you how to exchange a JWT for an access token: 

https://github.com/DinoChiesa/Apigee-Sample-Jwt-Bearer-Token-Exchange

Screencast here: https://youtu.be/z3VUaetWGmE