App Configuration URL endpoint

This endpoint is invoked by AMS on application configure. This topic explains the details of the request sent from AMS to an app when an app is configured. For information on the entire application configuration workflow see App Configuration.

Service URL

<app-base-url><app-configuration-url>

These URLs are registered with AMS when creating an app.

Request Method

POST

Request Header

Authorization: Bearer <JWT>

Content-Type=application/json

Bearer Token

JWT claims

When AMS is making the request to the app, the key and value pairs bear the following meanings:

Key Value Definition Context
iss The current issuer of the token. Set to "AMS".
sub The subject of the token. Set to the app's product UUID.
aud The audience of the token. Set to the app's Token Key.
exp The date and time the token will expire, expressed as a Unix timestamp. Must be after the current date/time. Set to 60 seconds after the JWT was created.
iat The date and time the JWT was issued, expressed as a Unix timestamp. Set to the current time.
jti The unique identifier for the JWT token. Set to a random UUID.
o.a.p.ctenantId The tenant Id. Set to the id of the tenant as identified by the product.
o.a.p.cproductUUID The product UUID. Set to the UUID of the product associated with the current installation.
o.a.p.cproductName The product name. Set to the name of the product, associated with the current installation.
o.a.p.csourceRequest The Source Id. Set to the UUID of the product associated with the current installation.
o.a.p.cdestinationId The destination Id. Set to the app's UUID. Found in app details.
o.a.p.cdestinationUrl The destination URL. Set to the app's Configuration URL.

Signature

Signed with an app's token secret.

Sample JWT Payload

In order to authenticate with the app, AMS constructs a JWT payload using the information details about the app (e.g application uuid, application token key, product affinity, etc). AMS then sign's the JWT using the application's token secret.

Below is an example JWT payload that AMS uses to call the app's Configuration URL endpoint:

{
  "iss": "AMS",
  "sub": "<app-product-uuid>",
  "aud": "280e7a65-ab6f-47ce-9dfd-0949fcca304c",
  "exp": 1549568114,
  "iat": 1549568054,
  "jti": "01ce7e7b-2a85-4b7a-b672-319a198c0582",
  "o.a.p.ctenantId": "607",
  "o.a.p.cproductUUID": "ba2e2ebc-2160-4ecc-b0d8-39f2ed20271f",
  "o.a.p.cproductName": "Product One",
  "o.a.p.csourceRequest": "<app-product-uuid>",
  "o.a.p.cdestinationId": "64658070-8290-4e2b-90d3-ec28fe01321e",
  "o.a.p.cdestinationUrl": "http://localhost:8090/api/appInstalls/configure"
}

Sample Request Body

{
    "applicationInstall": {
        "uuid": "some-application-install-uuid",
        "status": "UP",
        "deleted": 0,
        "application":{
            "baseUrl":"http://<application-baseUrl>/api/appInstalls",
            "configureUrl":"/configure",
            "description":"test app",
            ...
        }
    },
    "locale": "en-US"
}

Sample Response in case of success

The app's Configure URL endpoint should respond to AMS with HTML content that can be displayed as an iframe. It is up to the developer to determine the actual contents of the configure page. See App Configuration for details.

Sample Code

Sample App Implementation: Configuration URL Endpoint - Controller

//AppInstallController.java
@RequestMapping(value = "/configure", method = RequestMethod.POST)
public ModelAndView configureAppInstall(@RequestBody AppInstallCallDTO body,
    Map<String, Object> payload, @RequestHeader(value = "Authorization") String authorizationHeader) throws JSONException {
 
    String installUuid = body.getApplicationInstall().getUuid();
    AppInstall install = appInstallService.getEntity(installUuid);
 
    if(install == null) {
        throw new EntityNotFoundException("App Install Not Found => " + installUuid);
    }
 
 
    payload.put("appHostName", hostConfig.getHostname() + hostConfig.getPort());
    String apiKey = install.getConfigValue("apiKey") != null ? install.getConfigValue("apiKey") : "";
    payload.put("apiKey", apiKey);
 
    return new ModelAndView("installConfigure", payload);
}

Sample App Implementation: Configuration URL Endpoint - UI

//installConfigure.html
<form method="POST" class="mx-auto col-md-8" id="configuration-form">
    <h3 class="text-center" style="padding-top: 10px;">Enter the following app configuration: </h3>
    <div class="d-flex flex-row justify-content-around" style="padding-top: 5px;">
      <label class="col-sm-2 col-form-label col-form-label-xs">Open Weather Api Key:</label>
      <input class="form-control" type=text required id="apiKey" name="apiKey" value="{{apiKey}}">
    </div>
    <br>
    <div align="right">
        <input class="btn btn-info mb-2" type="button" id="ams-submit" onclick="saveForm()" value="Save" />
    </div>
</form>
 
<script>
    var appConfigSubmitter = new AmsAppConfigurationSubmitter();
    appConfigSubmitter.attachMessageListener();
 
    function saveForm() {
        var form = $("#configuration-form");
 
        // Get json from form fields with jquery magic
        var jsonObject = {};
        $(form).serializeArray().forEach(function(item){
            jsonObject[item.name] = item.value;
        });
 
        // Submit json to AMS
        $(".result").html("<div class=\"alert alert-info\" role=\"alert\">Saving...</div>");
         
        appConfigSubmitter.sendRequest(jsonObject, function(data) {
            if(data.httpStatusCode === 200) {
                $(".result").html("<div class=\"alert alert-success\" role=\"alert\">The install is successfully configured.</div>");
                statusMessageCommunication.postMessageSaveStatus("approved");
            } else {
                $(".result").html("<div class=\"alert alert-danger\" role=\"alert\">Failure save configuration: " + data.payload +"</div>");
                statusMessageCommunication.postMessageSaveStatus("refused");
            }
            console.log(data);
        });
    }
</script>

After the marketer has finished entering the input on the configure page and clicks Save, the app must send a postMessage to the parent AMS iframe.

Sample App Implementation: PostMessage

//configure.js
class BaseAmsCommunication {
    ...
    attachMessageListener() {
        var messageHandlerFunction = this.handleMessage.bind(this);
        window.addEventListener("message", messageHandlerFunction, false);
    }
    ...
    sendMessage(message) {
        window.parent.postMessage(message,'*');
    }
    sendRequest(messageOptions, handleMessageResponse, requestId, isProxyRequest, destinationUrl, requestType) {
        this.receivedMessage = false;
        this.handleMessageResponse = handleMessageResponse;
        var message;
        if(isProxyRequest === true){
            message = {amsAction : this.amsAction, requestId : requestId, destinationUrl : destinationUrl, requestType : requestType};
        }
        else {
            message = {amsAction : this.amsAction, requestId : requestId};
        }
        message = Object.assign(message, messageOptions);
        this.sendMessage(message);
        ...
    }
    handleMessage(event) {
        if(event && event.data) {
            console.log("Received Event From AMS", event);
            var data = event.data;
            if(data.requestId == this.amsAction || data.configurationStatus){
                this.receivedMessage = true;
                var response = this.parseResponse ? this.parseResponse(data) : data;
                this.handleMessageResponse(response);
            }  
        }
    }
}
  
class AmsAppConfigurationSubmitter extends BaseAmsCommunication{
    constructor() {
        super();
        this.amsAction = "saveappconfig";
    }
    sendRequest(jsonValues, handleSubmissionResponse) {
        super.sendRequest({payload: jsonValues}, handleSubmissionResponse);
    }
}

Note the following:

  • Notice that this.amsAction = "saveappconfig" will POST to the App's Save Configuration URL. Whereas t this.amsAction = "save" tells AMS to POST to the Service Instance's Save Configuration URL. These are different. Application configuration uses the former AMS action.
  • The Sample App is sending a payload in JSON, which is why the app can parse the JSON at the Save Configuration URL endpoint. AMS doesn't do any formatting to the payload.
  • The configure page should also implement a listener for the response of the Save Configuration URL. This is to display configuration Success or Failure to the user.

Learn more

Endpoint reference