How to access App custom attributes within Microgateway?

The client's use case is that they would like to store custom attributes on the App, product or developer and access those custom attributes from Microgateway. I reviewed the previous community post and also the Microgateway FAQs, which discuss this topic. The FAQ's provide a high-level approach to this. I will document the implementation of this high-level approach

Solved Solved
4 10 2,132
1 ACCEPTED SOLUTION

When Microgateway starts it downloads all the proxies (prefixed with edgemicro_), products, and apps and caches that data locally. However, you are not able to access custom attributes on those products. I was able to access the custom attributes on an Apigee App by injecting them as custom claims into the JWT when it is created. If you use access token validation, then you can access the custom claims on every request to Microgateway, which is similar to assigning custom attributes to an Apigee access token in Edge.

0) Add a custom attributes to the App.

3249-screen-shot-2016-07-27-at-124127-pm.png

1) Modify the edgemicro-auth proxy, by saving it as a new revision

a) Add an Extract Variable policy to the Preflow to retrieve the client ID from the JSON payload - client credential request.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ExtractVariables async="false" continueOnError="false" enabled="true" name="Extract-Client-ID">
    <DisplayName>Extract-Client-ID</DisplayName>
    <Properties/>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <JSONPayload>
        <Variable name="client_id">
            <JSONPath>$.client_id</JSONPath>
        </Variable>
    </JSONPayload>
    <Source clearPayload="false">request</Source>
    <VariablePrefix>flw.apigee</VariablePrefix>
</ExtractVariables>
	

b) Add an Access Entity policy to the Preflow to lookup the app custom attributes based on the client Id extracted in the previous step.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AccessEntity async="false" continueOnError="false" enabled="true" name="Access-Entity-1">
    <DisplayName>Access-Entity-1</DisplayName>
    <Properties/>
    <EntityIdentifier ref="flw.apigee.client_id" type="consumerkey"/>
    <EntityType value="app"/>
</AccessEntity>

c) Now you have to replace the content of api/controllers/volos-oauth.js file with the content from the volos-auth.js.txt file attached to this post.

I had to make some minor changes to this file for it to work. It is easier for you to download the attached file and copy it into your proxy, rather than explain what you need to change. Summary of changes below:

The first change I made was to add apigee-access, which allows a Node.js proxy to access Apigee Edge flow variables.

var apigee = require('apigee-access'); 

I also added the added the custom_attribute to the JWT payload, which references the Access Entity policy variable that is created when the policy executes.

var token = {
    application_name: apigeeToken.application_name,
    client_id: apigeeToken.client_id,
    scopes: apigeeToken.scope ? apigeeToken.scope.split(' ') : [],
    api_product_list: apigeeToken.api_product_list ? apigeeToken.api_product_list.slice(1, -1).split(',') : [],
    custom_attribute: apigee.getVariable(req, 'AccessEntity.ChildNodes.Access-Entity-1.App.Attributes.Attribute.4.Value')
  };


You may need to send an API request to determine the flow variable name of your App's custom attribute. In my case, it was stored in the variable below. You could also include an assign message policy to change the variable name to a more friendly version.

AccessEntity.ChildNodes.Access-Entity-1.App.Attributes.Attribute.4.Value

d) Save your changes.

e) When you submit an Access Token request via the microgateway cli, you will receive a JWT. Execute this command from the [path to edgemicro]/cli directory.

./edgemicro token get -o orgname -e env -i client_id -s secret

f) You can view the contents of the JWT with jwt.io and you should see the custom attribute(s) that you added once you decode the token.

2) Now you need to retrieve the value from the JWT when the request is submitted to Microgateway.

Microgateway will automatically validate and decode the token so that you can access the payload of the token from a custom plugin.

a) First you need to create a custom plugin; you can learn how to do this here, but I have already created it so you can download the extract-custom-claims.zip file and place it in your [path to microgateway]/plugins directory.

b) The last step is to update the {org}-{env}-config.yaml file, which holds Microgateway configuration. I have extracted a portion of that file below.

Notice that the "extract-custom-claims" plugin was added to the plugins - sequence section. This will make sure that our plugin executes after the OAuth plugin.

You can access the JWT custom attributes as shown below.

req.headers[header] =  req.token.custom_attribute;

Also notice that the "extract-custom-claims" is also added as a top-level item in the {org}-{env}-config.yaml file. This allows you to set values in the config file that are accessible from the plugin during run-time.

edgemicro:
  port: 8000
  max_connections: 1000
  max_connections_hard: 5000
  restart_sleep: 500
  restart_max: 50
  max_times: 300
  logging:
    level: info
    dir: /var/tmp
    stats_log_interval: 60
    rotate_interval: 24
  plugins:
    sequence:
      - oauth
      - extract-custom-claims
headers:
  x-forwarded-for: true
  x-forwarded-host: true
  x-request-id: true
  x-response-time: true
  via: true
oauth:
  allowNoAuthorization: false
  allowInvalidAuthorization: false
extract-custom-claims:
  username_header: x-username
  basic_auth_service_acct_user: serviceuser
  basic_auth_service_acct_pw: servicepassword

This is a snipet of the plugin code, which is also included in the attached zip.

//extract the username and password from the config file
var uname = config.basic_auth_service_acct_user;
var p = config.basic_auth_service_acct_pw;

If you send a request to Microgateway with a valid JWT token, then you should see some of the values print on the console, but they will also be injected into the request as custom headers to the target service.

Example of Microgateway request:

curl -i -H "Authorization: Bearer {valid_jwt}" "http://localhost:8000/edgemicro_hello/ping"

View solution in original post

10 REPLIES 10

When Microgateway starts it downloads all the proxies (prefixed with edgemicro_), products, and apps and caches that data locally. However, you are not able to access custom attributes on those products. I was able to access the custom attributes on an Apigee App by injecting them as custom claims into the JWT when it is created. If you use access token validation, then you can access the custom claims on every request to Microgateway, which is similar to assigning custom attributes to an Apigee access token in Edge.

0) Add a custom attributes to the App.

3249-screen-shot-2016-07-27-at-124127-pm.png

1) Modify the edgemicro-auth proxy, by saving it as a new revision

a) Add an Extract Variable policy to the Preflow to retrieve the client ID from the JSON payload - client credential request.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ExtractVariables async="false" continueOnError="false" enabled="true" name="Extract-Client-ID">
    <DisplayName>Extract-Client-ID</DisplayName>
    <Properties/>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <JSONPayload>
        <Variable name="client_id">
            <JSONPath>$.client_id</JSONPath>
        </Variable>
    </JSONPayload>
    <Source clearPayload="false">request</Source>
    <VariablePrefix>flw.apigee</VariablePrefix>
</ExtractVariables>
	

b) Add an Access Entity policy to the Preflow to lookup the app custom attributes based on the client Id extracted in the previous step.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AccessEntity async="false" continueOnError="false" enabled="true" name="Access-Entity-1">
    <DisplayName>Access-Entity-1</DisplayName>
    <Properties/>
    <EntityIdentifier ref="flw.apigee.client_id" type="consumerkey"/>
    <EntityType value="app"/>
</AccessEntity>

c) Now you have to replace the content of api/controllers/volos-oauth.js file with the content from the volos-auth.js.txt file attached to this post.

I had to make some minor changes to this file for it to work. It is easier for you to download the attached file and copy it into your proxy, rather than explain what you need to change. Summary of changes below:

The first change I made was to add apigee-access, which allows a Node.js proxy to access Apigee Edge flow variables.

var apigee = require('apigee-access'); 

I also added the added the custom_attribute to the JWT payload, which references the Access Entity policy variable that is created when the policy executes.

var token = {
    application_name: apigeeToken.application_name,
    client_id: apigeeToken.client_id,
    scopes: apigeeToken.scope ? apigeeToken.scope.split(' ') : [],
    api_product_list: apigeeToken.api_product_list ? apigeeToken.api_product_list.slice(1, -1).split(',') : [],
    custom_attribute: apigee.getVariable(req, 'AccessEntity.ChildNodes.Access-Entity-1.App.Attributes.Attribute.4.Value')
  };


You may need to send an API request to determine the flow variable name of your App's custom attribute. In my case, it was stored in the variable below. You could also include an assign message policy to change the variable name to a more friendly version.

AccessEntity.ChildNodes.Access-Entity-1.App.Attributes.Attribute.4.Value

d) Save your changes.

e) When you submit an Access Token request via the microgateway cli, you will receive a JWT. Execute this command from the [path to edgemicro]/cli directory.

./edgemicro token get -o orgname -e env -i client_id -s secret

f) You can view the contents of the JWT with jwt.io and you should see the custom attribute(s) that you added once you decode the token.

2) Now you need to retrieve the value from the JWT when the request is submitted to Microgateway.

Microgateway will automatically validate and decode the token so that you can access the payload of the token from a custom plugin.

a) First you need to create a custom plugin; you can learn how to do this here, but I have already created it so you can download the extract-custom-claims.zip file and place it in your [path to microgateway]/plugins directory.

b) The last step is to update the {org}-{env}-config.yaml file, which holds Microgateway configuration. I have extracted a portion of that file below.

Notice that the "extract-custom-claims" plugin was added to the plugins - sequence section. This will make sure that our plugin executes after the OAuth plugin.

You can access the JWT custom attributes as shown below.

req.headers[header] =  req.token.custom_attribute;

Also notice that the "extract-custom-claims" is also added as a top-level item in the {org}-{env}-config.yaml file. This allows you to set values in the config file that are accessible from the plugin during run-time.

edgemicro:
  port: 8000
  max_connections: 1000
  max_connections_hard: 5000
  restart_sleep: 500
  restart_max: 50
  max_times: 300
  logging:
    level: info
    dir: /var/tmp
    stats_log_interval: 60
    rotate_interval: 24
  plugins:
    sequence:
      - oauth
      - extract-custom-claims
headers:
  x-forwarded-for: true
  x-forwarded-host: true
  x-request-id: true
  x-response-time: true
  via: true
oauth:
  allowNoAuthorization: false
  allowInvalidAuthorization: false
extract-custom-claims:
  username_header: x-username
  basic_auth_service_acct_user: serviceuser
  basic_auth_service_acct_pw: servicepassword

This is a snipet of the plugin code, which is also included in the attached zip.

//extract the username and password from the config file
var uname = config.basic_auth_service_acct_user;
var p = config.basic_auth_service_acct_pw;

If you send a request to Microgateway with a valid JWT token, then you should see some of the values print on the console, but they will also be injected into the request as custom headers to the target service.

Example of Microgateway request:

curl -i -H "Authorization: Bearer {valid_jwt}" "http://localhost:8000/edgemicro_hello/ping"

Great Question & Excellent Answer @swilliams , Feel free to accept your own answer by clicking on Accept link below answer.

Hi @swilliams and @Anil Sagar, given the changes to the edgemicro-auth, is this still the best approach?. Volos and apigee_access have both been depreciated but this answer still depends on them.

Summary of Use Case:

We need to inject custom attributes from the App into the JWT.

Extract those custom attributes from the JWT in the Microgateway and forward them to the target service as custom headers.

We also need to include configuration data in from the config.yaml into the request to the target service.

This post describes how to implement this use case.

Not applicable

I'm trying to implement this for my microgateway implementation. I'm not familiar with volos-auth.js. What is this and where is it located? Is it in the microgateway implementation or is it something in the edgemicro-auth proxy? I see the file path you have indicated, but I don't understand where that is in the gateway implementation.

Hi, Jeremy,

The volos-auth.js file was for the original OAuth proxy that gets deployed when you execute the configure command. This is documentation needs to be updated for the more current OAuth proxy. It may even be easier with the new OAuth proxy, which uses our OOTB policies instead of the JavaScript callout. I'll have to write a new article/question to cover that.

Thanks for the response! I appreciate it! Question: will you be writing the article soon (this week or next) or can you provide any quick additional direction right now on what would need to be changed in the Oauth proxy to achieve what the modifications in the volos-auth.js was doing?

So I was able to accomplish what I needed by putting an additional claim in "Generate JWT"

<Claim ref="sourceSystem" type="string" name="source_system"/>

Next, I added the below line to Set JWT Variables to get the developer app custom attribute

var sourceSystem = context.getVariable('verifyapikey.Verify-API-Key.sourceSystemName') || 'NOT DEFINED';

context.setVariable("sourceSystem", sourceSystem);

In the Generate VerifyKey Token policy in the Verify API Key Flow I added an additional claim for the custom attribute

<Claim ref="sourceSystem" name="source_system" type="string"/>

This got what I needed into the JWT.

Then I modified the plugin you provided to do what I needed. This may not be the best way to achieve this, but I got it working for what I needed. I plan to investigate whether or not there is a better way so if I have more than one custom attributes it will get them without having to go in and add it every time.

Any thoughts on a better approach is appreciated! 🙂

Not applicable

Is there maybe a better way than the above and what I found? The way I described above works, but similar to your way described it 1. Puts something that I would rather not be in the jwt inside the jwt. 2. It seems like it will be challenging to maintain in that any additional custom attributes will have to be added in the same manner.

Is this just a limitation with the microgateway in that in order to get custom attributes we have to put them in the jwt?

Hi @Jeremy Smith,

This is the correct approach if you want to access custom attributes (per developer/app) from the Microgateway.

The alternative is to define properties within the Microgateway configuration file, which is also explained above.