Hi Community,
I am creating OAuth2 proxy for our GraphQL API endpoint. The API will be consumed by other services and different partners, our API is multi-tenant, so I need to identify the tenant on the API side. Since I am using OAuth2, on the API side I have access only to access_token - so I can't really identify the tenant.
What I have done so far:
User first hits generateAccessToken proxy ("https://example-eval-test.apigee.net/oauth/accesstoken") with key/secret combination they get access_token and then continue to use the API by attaching the access_token on the second proxy ("https://example-eval-test.apigee.net/graphql").
My dilemmas are:
I also had a look at JWT, Can I combine OAuth2 with JWT and have OAuth2 return JWT "access_token" so then I can easily decrypt that JWT token which will hold tenant data inside the API?
Solved! Go to Solution.
No. I am inferring by "key" you mean the API Key, also known as the client ID, also known as the consumer ID. And if that's what you mean, then the answer is no: don't use that. The reason is, this key may rotate, you may wish to expire it or revoke it, if it leaks or is lost. The model in Apigee allows you to configure a Developer, who owns multiple Apps, and for each app there can be multiple credentials (or keys). You want to use the Developer ID as the tenant ID. That way, if you revoke a key or create a new app under that developer, the tenant ID (Developer ID) remains stable.
Don't. when you use an Apigee policy like OAuth/VerifyAccessToken, Apigee will load into the message context the metadata you seek, like client id, and from that you can load in the Developer ID, aka Tenant ID, aka partner ID. Do not ask the client to pass that information.
The way you "load in" the Developer ID is via an AccessEntity policy. Check the documentation, look at videos, and look here in community for some examples. It's easy.
No. see above.
Can I combine OAuth2 with JWT and have OAuth2 return JWT "access_token" so then I can easily decrypt that JWT token which will hold tenant data inside the API?
Yes, you can do that too. I just wrote an article here on community about this. Check it out. I suggest that you don't NEED to use a JWT. You should use a JWT if there are good reasons to do it; Getting access to the tenant ID is not a good reason to use a JWT.
I assume if you are using the password grant type then you are validating the user against any identity and access management system before generating token.
1. You can use the consumer key as tenant id.
2. Access token is a Bearer token. So you should send that as Authorization header. You need not to send the key for service request. Once the access token is validated the key will be automatically available in the proxy flow.
3. You need not to send the tenant id if you are using the consumer key as tenant id.
Indeed, access token is sent as Authorization header on the proxy that verifies the token. The token is validated but the key is not automatically available in the flow, at least I can not see it. Can you please point me out how to access the key after access token is validated?
apigee.client_id is the variable that gives the client key after the oauth token validation.
As Dino specified the client id change may impact if you use client id as the tenant id, We have used the same client id as a custom attribute in the developer app as the tenant id or subscriber id, so it stands good in our case.
Still if you have any other Identity and access management system then you can use that as tenant id and validate that during the token generation flow and keep that available in the token using the attribute in the token generation.
Don't use the consumer key as the tenant ID. The consumer key may change, may get revoked, may get leaked. Don't depend on it never changing. See my answer.
No. I am inferring by "key" you mean the API Key, also known as the client ID, also known as the consumer ID. And if that's what you mean, then the answer is no: don't use that. The reason is, this key may rotate, you may wish to expire it or revoke it, if it leaks or is lost. The model in Apigee allows you to configure a Developer, who owns multiple Apps, and for each app there can be multiple credentials (or keys). You want to use the Developer ID as the tenant ID. That way, if you revoke a key or create a new app under that developer, the tenant ID (Developer ID) remains stable.
Don't. when you use an Apigee policy like OAuth/VerifyAccessToken, Apigee will load into the message context the metadata you seek, like client id, and from that you can load in the Developer ID, aka Tenant ID, aka partner ID. Do not ask the client to pass that information.
The way you "load in" the Developer ID is via an AccessEntity policy. Check the documentation, look at videos, and look here in community for some examples. It's easy.
No. see above.
Can I combine OAuth2 with JWT and have OAuth2 return JWT "access_token" so then I can easily decrypt that JWT token which will hold tenant data inside the API?
Yes, you can do that too. I just wrote an article here on community about this. Check it out. I suggest that you don't NEED to use a JWT. You should use a JWT if there are good reasons to do it; Getting access to the tenant ID is not a good reason to use a JWT.
Thank you for detailed explanation.
I successfully implemented the solution you advised.
So, when access token is verified via OAuth/VerifyAccessToken policy, I load the Developer ID with AccessEntity policy (I added custom attribute for the developers) and then I add that ID on the header to the target endpoint. This works fine.
Can I now verify that the tenant id on the header will never get compromised? Meaning, how can I make sure that tenant with valid access token always sends their tenantId. TenantId header is developer custom attribute, attached by Apigee policies, but still, I don't do any verification on application level and I have concerns that this header might be compromised by user with verified access token.
Can I create an policy that verifies that the tenantId header is always the same with the developer's attribute that is making the request?
Probably this is an edge case, but I would really like to an opinion on this.
Can I now verify that the tenant id on the header will never get compromised? Meaning, how can I make sure that tenant with valid access token always sends their tenantId. TenantId header is developer custom attribute, attached by Apigee policies, but still, I don't do any verification on application level and I have concerns that this header might be compromised by user with verified access token.
It sounds like you are concerned that an attacker might somehow know one or more tenantid's. And the attacker might send requests directly to the upstream, with a tenantid in the header. How will the upstream system be assured that the sender has validated a token, and has validated that the token is authorized for the tenantid? Is that right? Is that what you're concerned about?
There are multiple layers of security you can use to mitigate this risk.
These options are not mutually exclusive. Network security is most foundational. TLS is REQUIRED, in my opinion. And the application-layer signing may also be valuable if you are concerned about internal attackers exploiting TLS 0-day vulnerabilities.
Can I create an policy that verifies that the tenantId header is always the same with the developer's attribute that is making the request?
I don't understand this part of the question. I think the client in this case sends one thing - the token. Apigee stores the tenantid on the developer app - this is configured in some way, as a one-time action, at the time the client (api key) is provisioned. A good place to make this happen is in the developer portal. When your proxy validates the token, it extracts the tenantid from the developer account. We have certainty that the tenantid is valid for the token.
If you are concerned about leakage of tenantids, and the possibility that some attacker might send a request with a tenantid to the upstream, then you need to take one or more of the above steps to secure the connection between the Apigee proxy and the upstream.