Oracle CX Sales and Service - Outbound REST with x-www-form-urlencoded

April 16, 2020 | 3 minute read
Tim Bennett
CX Solution Architect
Text Size 100%:

Introduction

This article shows how outbound REST calls can be made from App Composer Groovy using a content type of x-www-form-urlencoded.

It assumes a basic knowledge of how to call REST APIs from Groovy and follows on from 2 articles on this subject:

https://www.ateam-oracle.com/engagement-cloud-rest-in-brief

https://www.ateam-oracle.com/engagement-cloud-outbound-rest-using-idcs-oauth

 

Note - the method is not described in CX Sales documentation.

 

Background

Engagement Cloud supports 2 payload formats when handling REST calls - JSON and XML. Irrespective of what the Content-Type is set to, the outbound message will be sent as one of these formats.

The method uses the fact that if a JSON formatted payload contains a urlencoded value, but the content type is set to x-www-form-urlencoded, the following happens:

Payload:

{
  "data": "scope=urn:opc:idm:__myscopes__&grant_type=client_credentials"
}

Received Form Values:

Form values
{"data":"scope urn:opc:idm:__myscopes__
grant_type client_credentials"}

 

Note, the receiver has treated the JSON payload as form data and has parsed it correctly into 2 form values (the form key/value pairs are separated by the &). Note what happens when the payload is "topped and tailed" with &:

Payload

{
  "data": "&scope=urn:opc:idm:__myscopes__&grant_type=client_credentials&"
}

 

Received form values:

Form values
{"data":" (empty)
scope urn:opc:idm:__myscopes__
grant_type client_credentials
"} (empty)

 

The above contains 2 empty form values with meaningless keys, and 2 "normal" values with the correct keys. As long as your endpoint ignores empty form values, it will accept and process the above JSON payload correctly as a x-www-form-urlencoded message.

 

App Composer Groovy Example

The method is illustrated via a contrived example which uses an Action button that makes 2 REST calls from Groovy and saves the retrieved details in a custom field. The high level Action button flow is:

Obtain a token from IDCS using the Client Credentials grant - this requires a x-www-form-urlencoded payload

Use the token to call the IDCS user endpoint

Save the user details in a custom field 

 

The purpose of the example is simply to illustrate the technique and is not necessarily a valid use case.

See https://docs.oracle.com/en/cloud/paas/identity-cloud/rest-api/op-oauth2-v1-token-post.html for the IDCS runtime OAuth REST endpoints.

 

IDCS Prerequisites

1) Create a Client Application in IDCS, making sure that Client Credentials is selected as an Allowed Grant Type

2) Note the Client ID and Client Secret

 

Engagement Cloud - App Composer configuration

1) Create web service references to the token endpoint, and user details endpoint:

/oauth2/v1/token  - use the Client ID and Client Secret from IDCS as the Basic credentials

/admin/v1/Users

 

2) Create a custom long text field called UserDetails_c on any object and expose it on a detail page

3) Create a new Action on the object and place the Action Button on the detail page

4) The Groovy on the Action button is:

 

// reference to IDCS token service
def tokenSvc = adf.webServices.tokenService

def headers = [:]
def params = [:]

//set the Content TYpe Header
headers.'Content-Type' = 'application/x-www-form-urlencoded'
tokenSvc.requestHTTPHeaders = headers

// put the form data into a single string with the pre/post &
def values = "&scope=urn:opc:idm:__myscopes__&grant_type=client_credentials&"

params.d=values

//call the service and retrieve the bearer token
def token = tokenSvc.POST(params).access_token

// reference to IDCS user service
def userSvc = adf.webServices.userService

// remove the content type header, set the Auth header to the Bearer token obtained above
headers.remove('Content-Type')
headers.Authorization="Bearer ${token}"
userSvc.requestHTTPHeaders = headers

// build filter for the current user
def queryParms = [:] 
queryParms.filter=("userName eq \"${adf.context.getSecurityContext()?.getUserName()}\"").toString()
println(queryParms.filter)

// apply the query parameters to the service 
userSvc.dynamicQueryParams = queryParms 

// Call the IDCS User Service
setAttribute("UserDetails_c", userSvc.GET())

 

 

Final thoughts

So far, this technique has only been tested with OAuth use cases - IDCS, Azure, and OPA. The Authorization mechanisms available in App Composer are enhanced on a regular basis, so perhaps it will become unnecessary, but in the meantime if it works for you, then use it.

 

Tim Bennett

CX Solution Architect

Solution Architect specialising in Oracle Sales Cloud configuration and integration, particularly security and scripting.


Previous Post

Using ODI Marketplace With Multiple Developers

Christophe Dupupet | 3 min read

Next Post


Create a semantic network and RDF support on Oracle Database Cloud Service 19c

Michael Shanley | 2 min read