Create a Custom AppID API

The Custom AppID API handles the workflow to call the AppID POST /token and the POST /introspect endpoints that constitute the OAuth OpenID Connect OAuth 2.0 authorization workflow. The GatewayScripts are responsible for parsing the incoming requests from the previous nodes and outgoing responses for the next nodes.

The Custom AppID API implements the same workflow as the optional Node-RED Test Server, but then embedded in the DataPower Gateway that is part of the API Connect instance.

  1. In API Connect Create a new API

    • Go to the API Connect Dashboard,

    • From the Home menu, go to Drafts,

  • Go to the APIs tab,

  • Create a new API and click the Add + button,

  • Select New API

  • Edit the API details:

    • Title: Custom AppID API,

    • Name, Base Path, and Version will auto-populate,

    • In Additional properties,

    • For Create API using template select Default,

    • For Target endpoint set /introspect,

    • Under Security, for Identify using select None,

    • Check Enable CORS,

    • Under Gateway select DataPower Gateway,

    • Click Create API,

  • Add New Path

    • Go to the Paths section,

    • Add a new Path and click the + icon,

    • Rename /path-1 to /introspect,

    • Click the Save icon,

  • Add the /token and /introspect Workflow to the Policy Assembly,

    • Go to the Policy Assembly section and click Edit assembly,

    • In the Assemble editor, a new assembly will load with a default invoke action,

  • In the Assemble editor, consecutively, create 3 GatewayScripts:

  • From the Policies section, drag a GatewayScript node onto the workflow, to parse the credentials of the incoming request,

    • Rename the Title to gs - credentials,

    • Paste the following Gateway script into the editor window,

var sm = require('service-metadata');

// decode username:password in Authorization header 
var authHeader = apim.getvariable('request.headers.authorization');
var encodedAuth = authHeader.replace("Basic ");
var decodedAuth = new Buffer(encodedAuth, 'base64').toString('ascii');
var credentials = decodedAuth.split(":");
var username = credentials[0];
var password = credentials[1];
var granttype = "password";

// handle optional x-introspect
var xUsername = apim.getvariable('request.headers.x-introspect-username');
var xPassword = apim.getvariable('request.headers.x-introspect-password');
var xGranttype = apim.getvariable('request.headers.x-introspect-granttype'); 
if(xUsername){
    username=xUsername;
}
if(xPassword){
    password=xPassword;
}
if(xGranttype){
    granttype=xGranttype;
}

// pass credentials
apim.setvariable('request.body.appid_username', username);
apim.setvariable('request.body.appid_password', password);
apim.setvariable('request.body.appid_granttype', granttype);
  • Save the Assemble to prevent loss,

  • From the Policies section, drag another GatewayScript node onto the workflow, to parse the user credentials from the previous step, and send a POST /token request to the Open ID Connect Identity Provider and receive the access_token, id_token, token_type, and expires_in the properties of the response,

    • Rename the Title to gs - token,

    • Paste the following Gateway script into the editor window,

var urlopen = require('urlopen');

var username = apim.getvariable('request.body.appid_username');
var password = apim.getvariable('request.body.appid_password');
var granttype = apim.getvariable('request.body.appid_granttype');

var requestData = `grant_type=${granttype}&username=${username}&password=${password}`;

var options = {
    target: 'https://<TODO APPID REGION>.appid.cloud.ibm.com/oauth/v4/<TODO: APPID INSTANCE ID>/token',
    method: 'POST',
    headers: {
        Authorization: 'Basic <TODO: BASIC AUTH WITH APPID CLIENTID AND SECRET>'
    },
    contentType: 'application/x-www-form-urlencoded',
    timeout: 60,
    sslClientProfile: 'webapi-sslcli-mgmt',
    data: requestData
};

urlopen.open(options, function(error, response) {
  if (error) {
    session.output.write("urlopen error: "+JSON.stringify(error));
  } else {
    var responseStatusCode = response.statusCode;
    var responseReasonPhrase = response.reasonPhrase;
    apim.setvariable('appid-token-response-statuscode', responseStatusCode); 
    apim.setvariable('appid-token-response-reason', responseReasonPhrase); 
    response.readAsJSON(function(error, json) { 
      if (error){
        throw error ;
      } else {
        apim.setvariable('request.body.appid_token_response_body', json); 
      }
    });
  }
});
  • Now we have the identity token, from the Policies section, drag a last GatewayScript node onto the workflow, to call the AppID POST /introspect API to validate the user's identity token,

    • Rename the Title to gs - introspect,

    • Paste the following Gateway script into the editor window,

var urlopen = require('urlopen');

var tokenResponseJson = apim.getvariable('request.body.appid_token_response_body');
var idToken = tokenResponseJson.id_token;
var requestData = `token=${idToken}`;

var options = {
    target: 'https://<TODO APPID REGION>.appid.cloud.ibm.com/oauth/v4/<TODO: APPID INSTANCE ID>/introspect',
    method: 'POST',
    headers: {
        Authorization: 'Basic <TODO: BASIC AUTH WITH APPID CLIENTID AND SECRET>'
    },
    contentType: 'application/x-www-form-urlencoded',
    timeout: 60,
    sslClientProfile: 'webapi-sslcli-mgmt',
    data: requestData
};

urlopen.open(options, function(error, response) {
  if (error) {
    session.output.write("urlopen error: "+JSON.stringify(error));
  } else {
    var responseStatusCode = response.statusCode;
    var responseReasonPhrase = response.reasonPhrase;
    apim.setvariable('appid-token-response-statuscode', responseStatusCode); 
    apim.setvariable('appid-token-response-reason', responseReasonPhrase); 
    response.readAsJSON(function(error, json) { 
      if (error){
        throw error ;
      } else {
        session.output.write(json);
        apim.output('application/json');
      }
    });
  }
});
  • The response of the last GatewayScript gs - introspectis a simple true|false value, which API Connect handles to return or proceed with the original API request,

  • From the top right menu, click the manage dropdown and select Generate a default product if you do not have an existing product,

  • Click Create product to create the New Product,

  • This will stage your new API to the Sandbox,

  • Click Explore and select Sandbox,

  • Click the POST /introspect operation in the left menu, and review the API reference values,

  • Copy the full URL, you need it to configure the Security Definition of your API, e.g. POST `https://api.<api region>.apiconnect.appdomain.cloud/<username>-dev/sb/custom-appid-api/introspect`,

Last updated