GetOAuthV2Info fails if token generated using product with resource paths

Not applicable

I have a proxy that provides 2 endpoints, one to generate access tokens using OAuthV2.GenerateAccessToken ("/accesstoken"), and the other to provide token attributes using GetOAuthV2Info.AccessToken ("/tokeninfo").

I also have 2 products, oauth-external and oauth-internal. oauth-external provides access to the proxy, but with the resource path set to "/accesstoken**", while oauth-internal provides access to the proxy, but without any resource path set. My understanding is that the resource path acts as a sort of restriction. So in this case, oauth-external will only allow calls to the "/accesstoken" endpoint.

I also have 2 applications, one that has access to oauth-external (ExternalApp), and the other to oauth-internal (InternalApp).

If I use ExternalApp to generate a token, I would expect InternalApp to be able to get the token attributes using the other endpoint. But I'm finding that GetOAuthV2Info.AccessToken will fail unless ExternalApp also has access to at least 1 product that has no resource path (restrictions) set. And it doesn't even have to be the other oauth product (oauth-internal). I can use a completely empty product that points to no proxies, as long as it doesn't have a resource path set. So in this case, I created a third product called empty-product with no proxies which I can add and remove to the ExternalApp.

One thing to note is that ExternalApp doesn't have to have access to empty-product at the time that the token is generated. Once the token is generated, adding empty-product to ExternalApp will allow InternalApp to get the token attributes as expected. Then removing empty-product from ExternalApp will cause the the failure to start occurring again. And so on.

I haven't tried splitting the two endpoints into separate proxies yet. If I do that, I'm assuming I can remove the resource path from oauth-external, but I'm wondering if the behavior I'm seeing is valid or not.

I am using the continueOnError attribute and <IgnoreAccessTokenStatus> element with the GetOAuthV2Info call.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <GetOAuthV2Info continueOnError="true" name="OAuthV2.GetTokenAttributes"> <AccessToken ref="request.formparam.token"/> <IgnoreAccessTokenStatus>true</IgnoreAccessTokenStatus> </GetOAuthV2Info>

In the request from InternalApp, I'm passing the client_id and client_secret in both the headers and the form parameters (I've tried just about every combination of this that I can think of).

curl -X POST \ http://myorg.apigee.net/myproxy/tokeninfo -H 'client_id: <api-key>' -H 'client_secret: <secret>' -H 'content-type: application/x-www-form-urlencoded' -d 'token=<token>&client_id=<api-key>&client_secret=<secret>'

0 10 1,976
10 REPLIES 10

Hmmm, ok I can understand your puzzlement.

one issue I believe you are seeing: is that if you configure an API Product with no proxies, tokens good for that API Product will be validated in *any* proxy. Your expectations may be counter to that reality. But the behavior I described is documented.

But one of us can look further into the scenario and see if we can help explain the other observations you've made. Let us get back to you.

Hey @Patrick Stadler --

I might be missing something about your use case from your description. But if I understand, you're trying to execute a GetOAuthV2Info policy on the /tokeninfo path of your proxy. I'd be curious to know what specific error you're getting when you say "it fails". Are you verifying your token *before* the GetOAuthV2Info policy executes and is that what's failing?

AFAIK, the GetOAuthV2Info policy doesn't by itself care how the Products related to a token are configured or whether you pass in a client_id or any other credentials. It just looks up information about the already generated OAuth token it receives and populates flow variables with that info if the token exists.

You're correct that you can use resource paths in products as a kind of filter to restrict access to certain resource paths in a proxy; however, that only applies if you use the OAuthV2.VerifyAccessToken policy to do token verification on the proxy endpoint. The VerifyAccessToken policy engages the logic that looks at the Products associated with a token and in that case, you could get an Auth exception if paths don't match up (e.g., the token was generated with a product that restricts calls to the /tokeninfo resource, and you try to call the /foobar resource). There are Apigee docs that talk about all this behavior that I could point you to. Dino is right that there are some details to be aware of when you're configuring products to restrict access to proxies, as explained in this article.

Please let us know if this helps or not. If I'm missing something about these behaviors, someone please chime in. 🙂

Will

Not applicable

@Dino and @wwitman

Thank you for your responses. I think I understand what you're saying about having the product with no proxies and no resource paths. I definitely don't want that to be my final solution.

Given that, I removed that empty product from ExternalApp. I also updated oauth-internal to have two resource paths: "/accesstoken**" and "/tokeninfo**" thinking that maybe both products having the overlapping "/accesstoken**" path would somehow help. I also added the VerifyApiKey to the PreFlow as suggested.

So I have the 2 products oauth-external and oauth-internal, both pointing to the same proxy, but one with a resource path of "/accesstoken**" (external) and the other with resource paths "/accesstoken**" and "/tokeninfo**" (internal). But it seems no matter what I try, I'm not able to get the token attributes through the oauth-internal product.

Basically what I'm trying to do is to allow an external application to generate a token, and then be able to get the attributes of that token from another application running internally. Is it possible to do that?

Hi Patrick -- It looks like I was wrong in my previous comment. I've been playing around with GetOAuthV2Info and find that it only works if the "resource path" used to get the token info is in the product that was used to generate the token in the first place. This seems to be what you're seeing, and it looks like this isn't documented clearly. This is the error I get if the product used to generate the toke does contain /accesstoken** but does NOT contain the /tokeninfo** path.:

POST http://myorg-test.apigee.net/oauth/tokeninfo (and I attach the token as a form parameter):

{
  "fault": {
    "faultstring": "Invalid API call as no apiproduct match found",
    "detail": {
      "errorcode": "keymanagement.service.InvalidAPICallAsNoApiProductMatchFound"
    }
  }
}

If I add the /tokeninfo** path to the product, then it the policy works as expected (after making the change I have to wait a few minutes for it to be recognized). I need to investigate a bit more to make sure this policy is documented correctly and that i'm not making any more incorrect assumptions.

Sorry for the confusions, but maybe this added info will help. Hopefully someone else will have a suggestion for you. But basically, you want to restrict access to the /tokeninfo path to only an internal client. Maybe there's another way to do that such as checking for a variable like client ip before GetOAuthV2Info executes.

yes, I think your observations are correct, Will. That agrees with what I saw.

Patrick, we should probably have a conversation about your real goals. What are you really trying to do?

GetOAuthV2Info isn't a whole lot different than OAuthV2.VerifyAccessToken, when you pass a token as input to the former policy. Furthermore, if what you want is information on the token itself, you already have it, after the proxy has executed OAuthV2.VerifyAccessToken. So it is pointless to execute a policy for GetOAuthV2Info after the proxy has already executed OAuthV2.VerifyAccessToken.

You *may* want to execute GetOAuthV2Info after OAuthV2.VerifyAccessToken, if you want to get information about other things, like the client itself . You would do this by executing GetOAuthV2Info and passing the client id, which is implicitly retrieved and placed into the MessgeContext via OAuthV2.VerifyAccessToken. [To complexificate things, there is also an additional related policy called AccessEntity that can retrieve information about entities like clients (apps), products, developers and so on. ]

Second thing - you don't need to include token dispensing flows in every apiproxy. You can have a single token dispensing proxy that serves for any API product. This proxy would have a OAuthV2.GenerateAccessToken policy. Then have separate proxies for doing... whatever else you want. These would include OAuthV2.VerifyAccessToken.

Hi Dino. My understanding is that OAuthV2.VerifyAccessToken will fail if the token is expired or revoked or anything else like that. In this case, I wanted to be able to get the token attributes even if the token is not valid at the time, so I used GetOAuthV2Info.

But given everything discussed here, I've added the "/tokeninfo" resource path to the external product as well as the internal. I can look at other ways to restrict access to that particular flow (such as an IP whitelist policy or something). That seems to be working.

Thank you both for all the information. I noticed that the documentation for this policy was updated based on this discussion. (Actually one of my coworkers noticed it, but in any case, that was quick!)

Thanks again.

(http://docs.apigee.com/api-services/reference/get-oauth-v2-info-policy)

How do I force Apigee to check for the details of a RefreshToken?. I have a GetOAuthInfo policy that gets the details of a refresh token generated from Internal Product which is generated from an External Product.

I don't wanna add the resource path of the GetOAuthInfo into External Product as this would expose the API into the clients. We only want to use this internally using the Internal Product that is registered to our App 2. Where App 1 is restricted only to access the External APIs which doesn't include the resource path of the GetOAuthInfo

Your question seems like a new one. Can you post a new question please, rather than posting a comment in a thread attached to a 2-year old question?

On second thought, I think I and @Will Witman have the same thoughts regarding implementing GetOAuthInfo where internal client could only access a specific resource path. Hence if I have /tokeninfo in Internal Product, only internal clients should be able to access it and not External Product where sensitive token details may be exposed. At the moment, I was forced to put the /tokeninfo resource path in the External Product making this API accessible to the public since I can't exclusively put it in Internal product to make it work since Apigee would error out.