Scope from Developer App Credentials

Hello,

I created a developer app using the apigee management api. When sending the developer app request I added scopes with it.

The consumer key created with the developer app seems to be an opaque token, so I wonder how I can extract the scopes using a policy on incoming requests. I want to extract the scopes and attach them as a new header (X-scope) in my request for use in my API.

Solved Solved
0 1 205
1 ACCEPTED SOLUTION

ok imma try to help you, but first we've got to take care with our terms, because different words mean different things.

  • The consumer key.
    also known as the consumer ID, or client ID. It can be used as an API key. It is not "a token".
  • The consumer secret.
    Also known as client secret. Can be used to generate crypto keys, for example, for HMAC. Also not called "a token".
  • OAuth token.
    This is a string that is returned from a token dispensary. Often client apps will present the client ID and client secret, in a request-for-token, as described in RFC 6749, under "client_credentials" grant type. Sometimes the token is "opaque", in other words it's just a random string, and it can be mapped to some set of claims only by the token issuer. But the token can also be a JWT, or some other form of non-opaque token. "Non opaque" means the holder of the token can "crack it open" (in the case of JWT, just base64-decode it) to see what claims are associated to the token.

ok you said

When sending the developer app request I added scopes with it.

Show me the request? In Apigee, you can set the possible scopes on each API Product. Then, when you create a developer app, you specify both an API Product, and optionally, a set of scopes. The set of scopes on the developer app must be a subset of the set on the API Product. A request to create an app looks like this:

 

POST :gaambo/v1/organizations/:org/developers/:dev/apps
Authorization: Bearer :token
content-type: application/json

{
  "name" : ":newAppName",
  "attributes": [{
     "name": "something",
     "value": "something-else"
    }
  ],
  "scopes": [
    "A",
    "B",
    "C"
  ],
  "apiProducts": [
    ":ProductName"
  ]
}

 

(Actually you can specify more than one API product on a developer app, and the set of scopes on the developer app must be a subset of the UNION of all scopes from all API products).

I wonder how I can extract the scopes using a policy on incoming requests.

When you create the developer app, you get credentials - a client id and secret. Then you can exchange those creds for a token. Normally the request-for-token is like this:

 

POST $endpoint/token
Authorization: Basic base64encode(client_id + ":" + client_secret)
content-type: application/x-www-form-urlencoded

grant_type=client_credentials&scope=REQUESTED_SCOPE

 

The REQUESTED_SCOPE is the scope the client is requesting on the token. (Assuming you configure the OAuthV2/GenerateAccessToken policy to use request.formparam.scope on in its Scope element configuration). Apigee will issue a scope that is the intersection of THAT requested scope, and the available scopes. Eg, if you request READ TRANSMOGRIFY, and the available scopes on the developer app are "READ UPDATE", then you will get a token with READ scope. If the client does not specify a scope in the request-for-token, the client will get all available scopes, as set on the developer app. If you don't have scopes set on the developer app, you'll get all available scopes on all the API Products that are set on the developer app.

In the response to request-for-token, you will see something like this:

 

{
  "token_type": "Bearer",
  "access_token": "u32IAKMSOGRaLlmz5bJB7O17jD8",
  "scope": "READ WRITE",
  "grant_type": "client_credentials",
  "issued_at": 1696433860,
  "expires_in": 1799
}

 

And right there you see the token, and the scopes.

Then, later when the client app USES the token, it passes the token, and you can specify in the OAuthV2/VerifyAccessToken policy, the scope to check. Eg "READ". Via the Scope element. And the policy will throw a fault if the provided token does not have that scope. You don't need to "examine" the scope directly. This is the usual way of employing scopes in Apigee.

I want to extract the scopes and attach them as a new header (X-scope) in my request for use in my API.

Which request? The request to the upstream system, made from Apigee? Or the request from the client into Apigee?

Also, WHY? What would be the purpose of attaching an X-scope header to a request? What is happening on the other end of that request? What will the receiver do with that header?

Maybe you want the upstream system to do its own authorization checks. Apigee just checks the scopes on the token and relays that to the upstream, and the upstream system decides whether to allow the request or not, based on the apigee-asserted scope. That could be reasonable.

The way to do this is to examine the scope context variable after the VerifyAccessToken policy completes. Then you could inject that as a header in the forthcoming request to the upstream, by using AssignMessage.

 

<AssignMessage name='AM-Inject-Scope-Header'>
  <Set>
    <Headers>
      <Header name='Scope'>{scope}</Header>
    </Headers>
  </Set>
</AssignMessage>

 

Also - It's possible to attach arbitrary custom attributes to a developer app when you create it, in the form of key/value pairs. The key can be any string (up to a point. There is a length limit, but I forget what it is atm). and you can retrieve these custom attributes in the same way, after VerifyAccessToken, by referencing the right context variable. And you can inject those things as headers for the upstream to consume. So if you want to go beyond "scope", you could do that.

View solution in original post

1 REPLY 1

ok imma try to help you, but first we've got to take care with our terms, because different words mean different things.

  • The consumer key.
    also known as the consumer ID, or client ID. It can be used as an API key. It is not "a token".
  • The consumer secret.
    Also known as client secret. Can be used to generate crypto keys, for example, for HMAC. Also not called "a token".
  • OAuth token.
    This is a string that is returned from a token dispensary. Often client apps will present the client ID and client secret, in a request-for-token, as described in RFC 6749, under "client_credentials" grant type. Sometimes the token is "opaque", in other words it's just a random string, and it can be mapped to some set of claims only by the token issuer. But the token can also be a JWT, or some other form of non-opaque token. "Non opaque" means the holder of the token can "crack it open" (in the case of JWT, just base64-decode it) to see what claims are associated to the token.

ok you said

When sending the developer app request I added scopes with it.

Show me the request? In Apigee, you can set the possible scopes on each API Product. Then, when you create a developer app, you specify both an API Product, and optionally, a set of scopes. The set of scopes on the developer app must be a subset of the set on the API Product. A request to create an app looks like this:

 

POST :gaambo/v1/organizations/:org/developers/:dev/apps
Authorization: Bearer :token
content-type: application/json

{
  "name" : ":newAppName",
  "attributes": [{
     "name": "something",
     "value": "something-else"
    }
  ],
  "scopes": [
    "A",
    "B",
    "C"
  ],
  "apiProducts": [
    ":ProductName"
  ]
}

 

(Actually you can specify more than one API product on a developer app, and the set of scopes on the developer app must be a subset of the UNION of all scopes from all API products).

I wonder how I can extract the scopes using a policy on incoming requests.

When you create the developer app, you get credentials - a client id and secret. Then you can exchange those creds for a token. Normally the request-for-token is like this:

 

POST $endpoint/token
Authorization: Basic base64encode(client_id + ":" + client_secret)
content-type: application/x-www-form-urlencoded

grant_type=client_credentials&scope=REQUESTED_SCOPE

 

The REQUESTED_SCOPE is the scope the client is requesting on the token. (Assuming you configure the OAuthV2/GenerateAccessToken policy to use request.formparam.scope on in its Scope element configuration). Apigee will issue a scope that is the intersection of THAT requested scope, and the available scopes. Eg, if you request READ TRANSMOGRIFY, and the available scopes on the developer app are "READ UPDATE", then you will get a token with READ scope. If the client does not specify a scope in the request-for-token, the client will get all available scopes, as set on the developer app. If you don't have scopes set on the developer app, you'll get all available scopes on all the API Products that are set on the developer app.

In the response to request-for-token, you will see something like this:

 

{
  "token_type": "Bearer",
  "access_token": "u32IAKMSOGRaLlmz5bJB7O17jD8",
  "scope": "READ WRITE",
  "grant_type": "client_credentials",
  "issued_at": 1696433860,
  "expires_in": 1799
}

 

And right there you see the token, and the scopes.

Then, later when the client app USES the token, it passes the token, and you can specify in the OAuthV2/VerifyAccessToken policy, the scope to check. Eg "READ". Via the Scope element. And the policy will throw a fault if the provided token does not have that scope. You don't need to "examine" the scope directly. This is the usual way of employing scopes in Apigee.

I want to extract the scopes and attach them as a new header (X-scope) in my request for use in my API.

Which request? The request to the upstream system, made from Apigee? Or the request from the client into Apigee?

Also, WHY? What would be the purpose of attaching an X-scope header to a request? What is happening on the other end of that request? What will the receiver do with that header?

Maybe you want the upstream system to do its own authorization checks. Apigee just checks the scopes on the token and relays that to the upstream, and the upstream system decides whether to allow the request or not, based on the apigee-asserted scope. That could be reasonable.

The way to do this is to examine the scope context variable after the VerifyAccessToken policy completes. Then you could inject that as a header in the forthcoming request to the upstream, by using AssignMessage.

 

<AssignMessage name='AM-Inject-Scope-Header'>
  <Set>
    <Headers>
      <Header name='Scope'>{scope}</Header>
    </Headers>
  </Set>
</AssignMessage>

 

Also - It's possible to attach arbitrary custom attributes to a developer app when you create it, in the form of key/value pairs. The key can be any string (up to a point. There is a length limit, but I forget what it is atm). and you can retrieve these custom attributes in the same way, after VerifyAccessToken, by referencing the right context variable. And you can inject those things as headers for the upstream to consume. So if you want to go beyond "scope", you could do that.