Multiple endpoint proxy security

I have an proxy created that has a base endpoint of /masterdata/version. Under this proxy, there are many true endpoints such as doing a retrieve (GET - /person/{id}) or an update (PUT - /person/{id}). These endpoints are not defined within the proxy as everything that hits the proxy, flows to the same back end service. Here is my issue, we now want to add deletes of data (DELETE - /person/{id}/phoneNumber/{phoneType}). This will flow through Apigee just fine to the back end. My issue is, I want different security on the delete. What I am thinking is having a different product that defines the delete path and then having a separate developer app that handles the delete as well. It would mean an additional call to get a new auth token when deleting but I am okay with that. Is this a good idea? How are others securing/locking down parts of a web service?

I thought about having a separate proxy, but I can not have the same base path for two different proxies.

0 1 244
1 REPLY 1

Under this proxy, there are many true endpoints such as doing a retrieve (GET - /person/{id}) or an update (PUT - /person/{id}). These endpoints are not defined within the proxy as everything that hits the proxy, flows to the same back end service.

I understand from this that there are no "flows" defined in the Apigee Edge proxy, to individually handle the different routes or endpoints in your API surface.

we now want to add deletes of data (DELETE - /person/{id}/phoneNumber/{phoneType}). This will flow through Apigee just fine to the back end. My issue is, I want different security on the delete. What I am thinking is having a different product that defines the delete path and then having a separate developer app that handles the delete as well. It would mean an additional call to get a new auth token when deleting but I am okay with that. Is this a good idea? How are others securing/locking down parts of a web service?

There are multiple ways to solve this problem.

First, as you mentioned, you can use a distinct API Product. The API Product artifact within Apigee Edge is designed to handle differential security and authorization within an exposed API surface. Suppose you have an elaborate API with /foo and /bar and you'd like to allow access to both /foo and /bar to one set of "consuming clients" and you'd like to allow access to only /foo to another set of consuming clients. You can

  • create distinct API Products with authorized resources. Product `1 has /foo and /bar, product 2 has only /foo
  • Create a Developer app (and a credential on that app) with authorization for Product1, and then another app (and credential) with authorization for Product2.
  • Use those credentials to obtain a token
  • Depending on the creds used to obtain the oauth token, at runtime an OAuthV2/VerifyAccessToken policy will allow, or won't allow, the request to pass through based on the path of the request.

This sort of works but it does not consider the Verb+Path combination that you want. Perhaps in your scenario a GET /person/{id}/phoneNumber/{phoneType} should succeed but DELETE on that Url path should fail.

OAuthV2 scopes might be a better way of handling this scenario. In fact OAuth2 scopes are intended to deal with this specific case.

Here's how THAT would work.

  • Define a single API Product, and specify a set of scopes on the product. The set of scopes is entirely up to you. A scope is just a name, a string, intended to communicate a "kind of thing permitted by a token with that scope". So you might have scopes like READ, WRITE, DELETE. or just READ, WRITE. Some API Providers define more elaborate scopes that are URIs. For example here is the link for scopes for Google Cloud APIs. Some examples for Stackdriver (the cloud logging and monitoring service) are:

    scope meaning
    https://www.googleapis.com/auth/trace.append Write Trace data for a project or application
    https://www.googleapis.com/auth/cloud-platform View and manage your data across Google Cloud Platform services

    An app that wanted to write data would need a token with the first scope. An app (or person) that wanted to view the data would need a token with the second scope.

  • Create at least one app, with a credential, authorized for that product.
  • At runtime, when the app requests a token (POST /token), it must specify the desired set of scopes. In the token dispensing endpoint, you can evaluate whether to issue the token with the requested scopes, based on the context in the request. For example, if this is an authorization code grant type, you will have some information about the human user who has been authorized by the IdP. And so if the IdP has asserted "this human is part of group 'employee'", then your token-granting logic can issue a token with scope "READ, DELETE", whereas if the human is not asserted to be part of the employee group, you can issue a token with scope "READ".
  • In the API proxy for the business API, include an OAuthV2/VerifyAccessToken that specifies a <Scope> element that includes DELETE, for the DELETE flow. Like this:

      <Flow name='del-phn-number'>
        <Request>
          <Step><Name>OAuthV2-VerifyAccessToken-WithDeleteScope</Name></Step>
        </Request>
        <Condition>(proxy.pathsuffix MatchesPath "/person/*/phoneNumber/*") and (request.verb = "DELETE")</Condition>
      </Flow>
    	

    and the verifyaccesstoken policy should specify the delete scope, like this:

    <OAuthV2 name='OAuthV2-VerifyAccessToken-WithDeleteScope'>
        <Operation>VerifyAccessToken</Operation>
        <Scope>DELETE</Scope>
    </OauthV2>
    

In this latter case, it's ok to call VerifyAccessToken twice. In the preflow, you might call VerifyAccessToken with the READ scope, which says "This proxy always requires at least a token with READ scope". And then ONLY for the DELETE flow, you can call a differently configured VerifyAccessToken policy to check for the DELETE scope. The token itself is cached so invoking two VerifyAccessToken policies in series will not result in a performance slowdown, even at scale. In this scenario, it would be just an in-memory check, quite fast.

Basically this approach simplifies the Authorization check at runtime for the delete operation to "does the token have the right scope"? And that's really easy to implement with the OAuthV2/VerifyAccessToken policy.

It does move some complexity into the token-issuance phase. this is where you have to decide, which app and which user is permitted to have a token with the DELETE scope?

By the way this approach also works with multiple API Products. You could provision two API Products, one with a list of scopes that includes READ, DELETE, and a second with only READ.

Then, provision apps, and embed the associated credentials into the applications you build. Any app with creds for the first API product can get a token with READ,DELETE scopes. Any app with creds for the second app will only ever be able to get a token with READ Scope.

This example shows a proxy that uses token issuance scopes (and via OpenID connect)