Functions – Refresh Access Token – Cognigy.AI Help Center
Functions – Refresh Access Token
Cognigy Support
April 29, 2022
There are many cases where you need an access token for an integration API. Since access tokens usually have a limited time span you will need to refresh those tokens occasionally. Depending on the API configuration you may be able to simply generate a new access token for each new Conversation. However, if that is not feasible you are left with the option to manually update the token or to use Cognigy Functions to automatically refresh it, this article will show you how.
Timeouts
There are a few things regarding timing that you must keep in mind:
- Functions have an execution time-limit, the default value is 15 minutes (900 seconds)
- Every Function will take some time to fully execute, how long exactly depends on the code
- The access token lifetime is probably longer than the Function execution time-limit
Based on these points the Function will have to re-trigger itself until the access token refresh time is within the current Function execution time-limit. Below you can see the life cycle:
Preparing the Endpoint
For this example, we will use a customized REST Endpoint that is storing the access token for channel integration API calls, you can find the REST Endpoint Transformer code below:
const INITIAL_TOKEN = {
"token": {
"access_token": "asdf",
"refresh_token": "asdf",
"expires_in": 2591999
},
"timestamp": 1625216009
}
const ENDPOINT_SECRET = "testTEST"
createRestTransformer({
/**
* This transformer is executed when receiving a message
* from the user, before executing the Flow.
*
* @param endpoint The configuration object for the used Endpoint.
* @param request The Express request object with a JSON parsed body.
* @param response The Express response object.
*
* @returns A valid userId, sessionId, as well as text and/or data,
* which has been extracted from the request body.
*/
handleInput: async ({ endpoint, request, response }) => {
const accessTokenStorage = await getSessionStorage("accessToken","accessToken")
if (!accessTokenStorage.token) {
console.log("initializing access token")
accessTokenStorage.token = INITIAL_TOKEN.token
accessTokenStorage.timestamp = INITIAL_TOKEN.timestamp
}
if (request.body.token &&
request.body.timestamp &&
request.body.endpointSecret == ENDPOINT_SECRET) {
accessTokenStorage.token = request.body.token
accessTokenStorage.timestamp = request.body.timestamp
console.log("updating access token " + JSON.stringify(accessTokenStorage.token) + ", timestamp: " + accessTokenStorage.timestamp)
response.sendStatus(200)
return null
}
console.log("access token: " + accessTokenStorage.token.access_token)
console.log("refresh token: " + accessTokenStorage.token.refresh_token)
const userId = undefined;
const sessionId = undefined;
const text = undefined;
const data = undefined;
return {
userId,
sessionId,
text,
data
};
},
handleOutput: async ({ output, endpoint, userId, sessionId }) => {
return output;
},
handleExecutionFinished: async ({ processedOutput, outputs, userId, sessionId, endpoint, response }) => {
return processedOutput;
}
});
As you can see in the example REST Transformer, we are checking whether the payload has the refreshed access token together with the timestamp and the Endpoint secret (to prevent unauthorized token refresh) and if so, we replace the access token in the access token storage. By using “response.sendStatus” and “return null” we respond that the request was correct and prevent the Flow Execution.
The code can also be added to the Inject/Notify Transformer for Endpoints that are not based on REST, the principle stays the same.
The Function
For your function you will need to gather two prerequisites:
- A valid Cognigy API key for re-triggering the Function. You can generate one in your profile, as long as you have the necessary rights
- The Function ID. This can be found in the URL once you have created your Function:
Below you can find the whole Function code with inline comments that should explain each step:
const API_KEY = "YOUR_COGNIGY_API_KEY"
const FUNCTION_ID = "URL_FUNCTION_ID_OF_THIS_FUNCTION"
const TOKEN_REFRESH_PERCENT = 90
const FUNCTION_TIME_LIMIT = 900
const FUNCTION_BUFFER = 5
export default async ({ parameters, api }: IFunctionExecutionArguments) => {
const { token, waitingTime } = parameters;
if (waitingTime >= ((FUNCTION_TIME_LIMIT + FUNCTION_BUFFER) * 1000)) {
const waitMilliseconds = (FUNCTION_TIME_LIMIT - FUNCTION_BUFFER) * 1000
const waiter = await new Promise(r => setTimeout(r, waitMilliseconds))
const response = await api.httpRequest({
method: "post",
url: "https://api-trial.cognigy.ai/new/v2.0/functions/" + FUNCTION_ID + "/trigger",
headers: {
"Accept": "application/json",
"X-API-Key": API_KEY,
"Content-Type": "application/json"
},
data: {
"parameters": {
"token": token,
"waitingTime": waitingTime - (FUNCTION_TIME_LIMIT * 1000)
}
}
})
} else {
const beforeTimestamp = moment(new Date()).unix()
const tokenResponse = await api.httpRequest({
method: "post",
url: "YOUR_REFRESH_TOKEN_URL",
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
}
})
const updateEndpointResponse = await api.httpRequest({
method: "post",
url: "REST_ENDPOINT_OR_INJECT/NOTIFY_API_URL",
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
},
data: {
"token": tokenResponse.data.token,
"timestamp": beforeTimestamp,
"endpointSecret": "testTEST"
}
})
const afterTimestamp = moment(new Date()).unix()
const waitMilliseconds = (beforeTimestamp - afterTimestamp + token.expires_in) * TOKEN_REFRESH_PERCENT * 10
const response = await api.httpRequest({
method: "post",
url: "https://api-trial.cognigy.ai/new/v2.0/functions/" + FUNCTION_ID + "/trigger",
headers: {
"Accept": "application/json",
"X-API-Key": API_KEY,
"Content-Type": "application/json"
},
data: {
"parameters": {
"token": tokenResponse.data.token,
"waitingTime": waitMilliseconds
}
}
})
}
}
Functions
- Handling a welcome message with Transformers and Endpoints
- Functions – Refresh Access Token
- Functions Overview
Table of contents
Timeouts
- Preparing the Endpoint
- The Function