Authorization: Bearer Token Help with Configuration

Hi, I apologize for the inexperience with this request, but I need some guidance and figured I would post something here to see if I can get some guidance from the community. I’ve outlined what we are trying to accomplish below with the hopes of confirmation if this is the correct approach or guidance on how we should proceed with the setup.

A bit of background, last year we migrated into PureCloud and set up with the assistance of professional services our IVR routing path. This configuration was using data actions connecting to our CRM to accomplish the following: 1. Identify callers via ANI match. 2. If no ANI match, prompt for account number. That configuration is working fine in the architect; however, we are moving into a different CRM that requires a different form of Authentication which we are not as familiar with and need help with. Authentication via Bearer Token. Not sure if the steps I've taken so far are correct so all feedback will be appreciated.

Here is an example of what we are trying to accomplish with the new CRM:
GENESYS - POST : CRM URL - Login/Validate via token bearer using account number or phone number -->
<-- CRM Response : access token to GENESYS Architect
GENESYS - GET user profile information with authorization token bearer -->
<-- CRM Response : User profile information back to Architect

I have set up two different data action in integration:

  1. POST: request token bearer : Returns token – It works but I am not sure about the “contract” input\output configuration. I need help\clarity on how it should be configured if I have the correct approach.
    {
    "data.agent_type": " data agent type here",
    "data.cust_id": "data cust id here",
    "code": "000",
    "data.refresh_token": " refresh token here",
    "data.scope": " data scope here",
    "data.token_type": "bearer",
    "data.expires_in": 2591999,
    "data.agent_id": " data agent id here ",
    "data.jti": " ",
    "message": "Ok",
    "data.access_token": "token here",
    "data.rep_acct_nr": " account info here"
    }

  2. GET: User Profile using bearer token
    Header: Authorization: Bearer (followed by token) I only get a response when the token is included in the “header.”
    {
    "code": "000",
    "message": "Ok",
    "data": {
    "accountNumber": (data),
    "firstName": "(data)",
    "lastName": "(data",
    “etc…”
    }

Hi Jaime,

Take a look at this documentation and see if it answers your questions:

--Jason

Hi again,

The documentation above assumes that one bearer token will work for all of you user profile lookups. One of my coworkers mentioned that he was under the impression that you may need to generate a different token for each profile lookup, in which case your approach of creating two data actions would be the way to go.

In the first data action you would need to either model the data object, including the access_token, or you could use the translation map (something like $.data.access_token) and then put the result into a variable in the success template.

It looks like you have the right idea with the second data action.

--Jason

Hi Jason,

Thank you for confirming that I am on the correct path. I appreciate the assistance. Yes, the token will be requested per each profile lookup. However, as I am setting up the translation to run the token using the recommended mapping, I am getting a "400" error message. I've tried several different translations but it's registering incorrectly when I run the test. Is my translation mapping correct?

Translation Mapping:
{
"translationMap":{"access_token": "$data.access_token"},
"translationMapDefaults": { "access_token": "null"},
"successTemplate": "{\r\n "access_token":$access_token"
}

Returned Error Message:
{
"message": "Transform failed to process result using 'successTemplate' template due to error:'Unexpected end-of-input: expected close marker for Object (start marker at [Source: (String)"{\r\n "access_token":null"; line: 1, column: 1])\n at [Source: (String)"{\r\n "access_token":null"; line: 2, column: 24]'\n Template:'{\r\n "access_token":$access_token'.",
"code": "bad.request",
"status": 400,
"messageParams": {},
"contextId": "aac9af41-8249-4bb5-80e6-0a865f267351",
"details": [
{
"errorCode": "ACTION.PROCESSING"
}
],
"errors": []
}

In your translation map there should be a dot between the $ and data. One of the test mode steps will show you the results of the translation map JSON Path processing. I recommend using this web site to test out your jsonpath on results of the execute step (the response from the external web service).
http://jsonpath.herokuapp.com/

Hello,

If the response body of your first request is in this format (attributes named "data.xxxx") like:

{
    ...
    "data.access_token": "token here",
    ...
}

You can use the following Response configuration:

{
  "translationMap": {
    "access_token": "$[\"data.access_token\"]"
  },
  "translationMapDefaults": {
    "access_token": "\"\""
  },
  "successTemplate": "{ \"access_token\": ${access_token} }"
}

If the response body of your first request is in this format (attributes inside a "data" object/structure) like:

{
    "data": {
        ...
        "access_token": "token here",
        ...
    }
}

You can use the following Response configuration:

{
  "translationMap": {
    "access_token": "$.data.access_token"
  },
  "translationMapDefaults": {
    "access_token": "\"\""
  },
  "successTemplate": "{ \"access_token\": ${access_token} }"
}

Regards,

Hi,

@Jason, thanks for sharing the website for testing. Much appreciate the support! @Jerome, thank you for jumping in and providing additional help here. Below is the response and it gave me an " Action successfully run" output when I used the second response body. This is great! However, should I expect to see the actual token in the "contract" "output"? It's returning blank with the below JSON response.

{
"access_token": ""
}

API Response:
{
"code": "000",
"message": "Ok",
"data": [
{
"access_token": " ",
"token_type": " ",
"refresh_token": "",
"expires_in": ,
"scope": "",
"agent_type": "",
"agent_id": "",
"rep_acct_nr": "",
"cust_id": " ",
"jti": " "
}
]
}

Thank you!

You are showing another response body. I mean a different format from your original question :slight_smile:
The translationMap depends on what you expect as an answer.

So it is not "data.access_token".
It is not a "data" object structure, with an attribute "access_token" inside.
It is a "data" array attribute, containing objects with an attribute "access_token" inside.

In this case, you should use the following Response configuration:

{
  "translationMap": {
    "access_token": "$.data[0].access_token"
  },
  "translationMapDefaults": {
    "access_token": "\"\""
  },
  "successTemplate": "{ \"access_token\": ${access_token} }"
}

Regards,

@Jerome you can tell I am very new to java and JSON :crazy_face: :upside_down_face: - Now that I updated the code, it gave me the correct output. THANK YOU so MUCH for the support!! :clap: - Now, I can move on to the next API which is where I would retrieve my profile information. I may need some help there too but once these are setup, I can probably manage all the updates in "architect" (I hope).

No problem at all Jaime. We all have to start on something one day :slight_smile:

1 Like

@Jerome, now that I am configuring the API to retrieve the profile information, I am running into an issue with the "success path." I'm assuming that I should follow the same array format you provided and I was thinking that the comma (,) would separate each success path but it's not accepting it. It worked through translationMap\MapDefaults but not for the success path. Can you kindly tell me how to separate them in the correct format?

Here is my success path:
},
"successTemplate": "{ "accountNumber": {accountNumber} }","{ \"firstName\": {firstName} }","{ "lastName": {lastName} }","{ \"etc\": {etc} }",
}

Can you post a response body of the profile info (your second request I assume)? That will be easier for me to give you a complete answer (as I am off on PTO starting at the end of the day - in 30 mn or so).

@Jerome Here is the body response. Thanks.
{
"code": "000",
"message": "Ok",
"data": {
"accountNumber": ,
"firstName": "",
"lastName": "",
"birthDayDate": "",
"langCode": "",
"levelSalesCode": "",
"campaignCount": ,
"statusCode": "",
"accountBalance": ,
"termsCode": ,
"cartItemCnt": ,
"levelLeaderCode": "",
"creditLimit": ,
"disabilityTag": ,
"phoneNumber": "",
"addtionalPhoneNumber": ,
"address": "",
"zipCode": "",
"blockTag": "",
"emailAddr": "",
"lastOrderNo": "",
"levelLeaderName": "",
"premiere":
}

So no array this time? I mean no "data": [....] (the square brackets represent an array in JSON).

I'll take advantage of this to explain one thing regarding the Response configuration and the Output Contract. I am just showing a subset of your data (short on time to do them all - but you should get the picture).

Approach 1)

The name of the variables/parameters you use in your Output Contract (the output parameters you will have in your Data Action) do not need to match the attribute names you get in the profile response.
That's what translationMap and successTemplate is about (I mean one of the things you can do with it).
If you define an output parameter (in your output contract) with name "CustomerAccountNumber", it means you will have to use it when you build your successTemplate.

The second thing is about the "temporary" variables you use in your translationMap.
They do not need to match the attribute names you get in the profile response.
They do not need to match the output parameter names you use in your Output contract. That's just a "temporary" variable used in the processing.

I am not saying that the names for the Output parameter, for the translationMap variable and for the response body attribute names must be different. You can use the same.
I am just trying to say that you are not obliged to - as long as you tie them properly (between Output Contract, translationMap and successtemplate).

So your Output Contract (JSON form) could be:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "Customer Profile Information",
  "type": "object",
  "properties": {
    "CustomerAccountNumber": {
      "type": "string"
    },
    "CustomerFirstName": {
      "type": "string"
    },
    "CustomerLastName": {
      "type": "string"
    },
    "CustomerBirthDayDate": {
      "type": "string"
    },
    "CustomerLangCode": {
      "type": "string"
    }
  },
  "additionalProperties": true
}

And your Response Configuration (this time your "data" attribute is apparently an object and not an array of objects):

{
  "translationMap": {
    "varAccountNumber": "$.data.accountNumber",
    "varFirstName": "$.data.firstName",
    "varLastName": "$.data.lastName",
    "varBirthDayDate": "$.data.birthDayDate",
    "varLangCode": "$.data.langCode",
  },
  "translationMapDefaults": {
    "varAccountNumber": "\"\"",
    "varFirstName": "\"\"",
    "varLastName": "\"\"",
    "varBirthDayDate": "\"\"",
    "varLangCode": "\"\""
  },
  "successTemplate": "{\n \"CustomerAccountNumber\": ${varAccountNumber},\n \"CustomerFirstName\": ${varFirstName},\n \"CustomerLastName\": ${varLastName},\n \"CustomerBirthDayDate\": ${varBirthDayDate},\n \"CustomerLangCode\": ${varLangCode} \n}"
}

Approach 2)

I will now explain one second thing. I hope this won't bring confusion.
But based on your response body, you don't need a lot of transformation in your translationMap.

So a second approach would be to simplify the translationMap, and rely on the fact that the Output Contract parameter names match what you have in your response body (as attribute names, under the data structure).

So your Output Contract (JSON form) could be:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "Customer Profile Information",
  "type": "object",
  "properties": {
    "accountNumber": {
      "type": "string"
    },
    "firstName": {
      "type": "string"
    },
    "lastName": {
      "type": "string"
    },
    "birthDayDate": {
      "type": "string"
    },
    "langCode": {
      "type": "string"
    }
  },
  "additionalProperties": true
}

And your Response Configuration (this time your "data" attribute is apparently an object and not an array of objects):

{
  "translationMap": {
    "varData": "$.data"
  },
  "translationMapDefaults": {},
  "successTemplate": "${varData}"
}

In this case, we are passing the data object content directly in the successTemplate.
You then just need to define Output Contract parameter names which match the attribute names of your data object, if you want to extract them.

Regards,

1 Like

Thanks @Jerome! Have an excellent time off.

@Jerome not sure if you are back in the office? I received a successful return with Approach #2). Thank you very much for both explanations! :star_struck:

However, now I ran into a new issue with the token itself. When I run the API, it's not registering the token in the "input" which is where I thought it would need to be connected. When I paste the token in the "Header" within the configuration, it acknowledges it. Is there a way that I can connect the token to be registered as an input within the contracts?

Hello,

I assume you are referring to your second request.
Getting the access_token as output of the first request, and then using it as input of the second request.

Can you post what you have in your Request Configuration (select JSON so you can get requestUrlTemplate, requestType, headers, ... in a JSON structure)?
Just make sure to redact/replace what's secret - before posting.

Regards,

Hello! This is the JSON format I have in the request. I copied the API from the token but I don't think I need to have the client info in the body.

{
"requestUrlTemplate": "API URL HERE",
"requestType": "GET",
"headers": {
"Authorization": "Bearer (token here)",
"Content-Type": "application/json"
},
"requestTemplate": "{\n "client_id": "ID HERE",\n "client_secret": "CLIENT SECRET HERE",\n "account_number": "${input.account_number}",\n "agent_id": "string"\n}"
}

Contract input:

{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema#",
"properties": {
"access_token": {
"type": "string"
}
},
"additionalProperties": true
}

I don't understand why you have set something in your requestTemplate.
You are sending a GET - so most likely your body will be empty.
Or you just copied the Data Action of your first request, and didn't change this piece in the second (given you are also referencing an input named account_number into it, which is not defined in your Contract Imput).

You can use the following (assuming your request body - i.e. requestTemplate - is not used in your second request).

{
  "requestUrlTemplate": "YOUR API URL",
  "requestType": "GET",
  "headers": {
    "Authorization": "Bearer ${input.access_token}",
    "Content-Type": "application/json"
  },
  "requestTemplate": "${input.rawRequest}"
}

Regards,

I noticed I left that request template in body as a duplicate (not sure why). Let me update and see if it works. Thanks!