Validate external JWT Token globally

Hi Folks,

I have question for the scenario when I have an external oAuth provider and inside the oAuth authorization we have a JWT token with information of the user, like user contract_id.

We use access_token for authentication and authorization.

When I call apis from the front-end, I send the contract_id as path parameter, request parameter, headers, anyway. It's dynamic and it depends on Api for each situation, when i have this contract_id, i should decrypt JWT token and check if this contract_id belongs to this user, if not I return 401.

We've tried to extract data gloabally considering KVM, but I saw there are KVM limits on

https://docs.apigee.com/api-platform/reference/limits, or the best practice in this case is use extract variables and JWT Validation for each api proxy.

Thanks in Advance

0 5 384
5 REPLIES 5

Not applicable

JWT verify is the best way for each api proxy. You can have some parameters as claims in the token. Once the token is verified in Apigee, the content will be available in Apigee flow.

When I call apis from the front-end, I send the contract_id as path parameter, request parameter, headers, anyway. It's dynamic and it depends on Api for each situation, when i have this contract_id, i should decrypt JWT token and check if this contract_id belongs to this user, if not I return 401.

Can you explain what a request looks like, specifically? Let's not discuss 5 different ways to send contract id. Just for simplicity, can we confine our discussion to just one way? for example, sending the contract id in a Header.

Where does the JWT go? How does it travel from client to Apigee? What does a full request from client to Apigee look like? Maybe give a concrete example.

It sound like you want to validate one data item from the request (contract id) against another data item in the request - a claim in the JWT. But you also wrote:

We've tried to extract data gloabally considering KVM, but I saw there are KVM limits on

...and I am not at all clear how that relates to "validating one part of a request against another part of the request."

Can you try to clarify that for me? After I better understand what you want, maybe I'll be able to provide some perspective.

Let me clarify

Considering the following apis:

Api 1

Endpoints
GET product/v1/{contractId}/{code}/products/
GET product/v1/{contractId}/{code}/products/{productId}
POST product/v1/{contractId}/{code}/products/
PUT product/v1/{contractId}/{code}/products/{productId}

Api 2

Endpoints
GET items/v1/{contractId}/{code}/products/{productId}/items
GET items/v1/{contractId}/{code}/products/{productId}/items/{itemId}
POST items/v1/{contractId}/{code}/products/{productId}/items
PUT items/v1/{contractId}/{code}/products/{productId}/items/{itemId}


Api 3

Endpoints
GET invoices/v1/invoices?contractId=99999&code=0000


Considering:

- To access these apis I have to provide an access_token.
- Access token is OpenId and contains a JWT with Claims
- Claims are "contractId" and "code"

Option number one:
I can import these 3 apis as Api Proxies on Apigee
For Api 1 and 2 i can extract variables and use JWT Verify to compare to claims values in JWT Token and authorize.
For Api number 3, i can extract variables, but from query string

Option number two:
I can create a global shared flow to do the JWT validation and use KVM to change the scenario for each api proxy. Example:

KVM Key: ApiProxy1__GET Value: {"contractId": "pathparam.0", "code":"pathparam.1"}
KVM Key: ApiProxy1__POST Value: {"contractId": "pathparam.0", "code":"pathparam.1"}
KVM Key: ApiProxy1__PUT Value: {"contractId": "pathparam.0", "code":"pathparam.1"}

KVM Key: ApiProxy2__GET Value: {"contractId": "pathparam.0", "code":"pathparam.1"}
KVM Key: ApiProxy2__POST Value: {"contractId": "pathparam.0", "code":"pathparam.1"}
KVM Key: ApiProxy2__PUT Value: {"contractId": "pathparam.0", "code":"pathparam.1"}

KVM Key: ApiProxy3__GET Value: {"contractId": "query.contractId", "code":"query.code"}

Conclusion

The option number 2 make things easier for developer, because they don't need to put policies on api proxy.
But I do need to crate a lot of KVM's and we can reach the Apigee limits.
The option number 1 seems to have a lot of repetitive work.

I'd like to get your opinions to avoid future issues.

I see. I think I understand better now, thanks.

I understand what you wrote about the KVM approach, in which you codify where the contract id lies in the request as well as within the JWT.... The way you've imagined the data format for the KVM... a single entry per tuple of {proxy, verb}... is reasonable but as you not, it results in a sort of explosion proliferation of KVM entries. Do you need all of that?

Maybe a better way to do it is to store a larger JSON in just ONE KVM entry. And maybe since in each particular proxy, the contract ID always appears in the same place regardless of the verb (the leftmost path segment or the well-known header), you could collapse all the special cases. Resulting in data that might look like this:

<br>{ 
  "locationOfContractId" : {
    "proxy1" : "path",
    "proxy2" : "query",
    "proxy3" : "header"
  },  
  ...other config stuff here ...
}

And the KEY for this thing is "datamap" or something generic like that.

Use a single KVM to read the configuration (and then cache it implicitly), and then use a jsonpath lookup (relying on the apiproxy.name context variable) to extract the information you want for your particular proxy.

Then use a Condition that examines the output of that jsonpath query to execute one of two ExtractVariables policies - one that extracts the contract id from the left-most path segment, the other that extracts it from the well-known header. If you also want to alow the contractID to be passed in a query, then you will need another ExtractVariables for the well-known query parameter.

And then finally validate the extracted contract ID against the contract ID asserted in the JWT.

This doesn't sound like very much work. It feels like maybe 4-5 policies and one KVM entry. You can update the KVM as necessary, when you add proxies or extend things.

Does this make sense?

Now, one more comment, if REALLY there are just three APIs, and you don't have a roadmap in which there will be 15 or 20 more APIs joining the party soon, then....maybe you don't need to go meta with the configuration in the KVM. You can just define a SharedFlow and "hard-code" the condition so that it checks, "is this proxy1 or proxy2? then run the ExtractVariables to pull contractID from the path, else use ExtractVariables to pull the contract ID from the header." In other words, embrace the Keep it Simple philosophy, unless you really expect a larger number of proxies.

helpful?

Very helpful,

I give you an example of 3 apis, but in fact i have a lot of apis.

Thanks.