REST API with Arbitrary Token Authentication

A component for REST requests with the ability to generate Token Code code in configuration fields.

The component is tailored for REST requests and can generate Token Codes in configuration fields. Instead of creating two separate steps, this single step in the flow enables seamless interaction with the REST API.

Upon execution, the code generates an object containing two functions: addAuthenticationToRequestOptions and getAccessToken.

These functions can be subsequently executed with the provided code operations.

Credentials

Base URL

If provided, all requests made with the action should be appended to this base URL (account for trailing / chars in an intelligent way).

Config Data

Arbitrary JSON that can store information required to obtain the auth token (for example, Username, Password, Token URL).

Token Code

JS Code that, when evaluated, produces an object with two properties; addAuthenticationToRequestOptions and getAccessToken() More explanation of these functions is included in the JS code.

async function addAuthenticationToRequestOptions(requestOptions)

This function takes one option, requestOptions. It modifies requestOptions to include additional authentication fields. Accesses credential information through this.cfg. Calls the async function this.getTokenAndUpdateCredentials().

async function getTokenAndUpdateCredentials()

Calls getAccessToken() to obtain authentication tokens. Saves the returned data into the Tokens field of the credential. Returns a JavaScript object containing authentication tokens. Calls this.getCredentials() to ensure current token information. async function getAccessToken() makes necessary call(s) to obtain authentication tokens. Returns a JavaScript object that updates the Tokens field of the credential. Calls this.getCredentials() to ensure current token information.

Libraries available:

  • Axios

  • xml2js

    Tokens

    Place to store access tokens and other received metadata (for example, expiry time)

Triggers

This component has no trigger functions. This means it will not be accessible to select as a first component during the integration flow design.

Actions

HTTP Request Action

This action makes an HTTP request with described parameters and options and parses the response to the flow.

Configuration fields description

Error Tolerance

A required drop-down. Determines behavior for when an erroneous HTTP code is received. The options are as follows:

No Errors Tolerated

Any HTTP status code >= 400 should result in an error being thrown

Only Not Found Errors Tolerated

HTTP status codes of 404, 410, or similar should result in a message being produced with the status code and the HTTP response. All other error codes should result in an error being thrown.

None

Regardless of the HTTP error code, the component should produce an outbound message with the status code and the HTTP response.

Manual

A range of error codes to throw errors on can be configured through the message input.

In this component, authorization generates a token and stores it in JSON-formatted credentials. When a new REST request is called, the component examines the credentials and takes the token from there if it is present.

If the token is valid, the component makes this request with parameters and the obtained token. If the token is not valid, then a new token is generated.

The following diagram shows how REST calls will be handled with request options and how to add an authentication token. When you implement these two functions (addAuthenticationToRequestOptions() and getAccessToken()) in the REST client, the following will happen:

flowchart 1

As shown, the addAuthenticationToRequestOptions() function is called before making a request, and it is your responsibility to implement it. The this.getToken() function is available here; you can use the following code:

async function addAuthenticationToRequestOptions(requestOptions){
  const accessToken = await this.getToken();
  requestOptions.headers.Authorization = `Bearer ${accessToken}`;
}

The following diagram describes the function getToken():

flowchart 2

As you can see, the getToken() function uses the getTokenAndUpdateCredential() function, which is also available at addAuthenticationToRequestOptions() and described below.

flowchart 3

As you can see, the getTokenAndUpdateCredential() function uses the getAccessToken() function, and it is your responsibility to implement it.

The getAccessToken() function should return an object with the required property: access_token. Property expires_in is optional and will be used in the calculation token expire time.

See code example:

async function getAccessToken() {
  const { tokenUrl, username, password, data } = JSON.parse(this.cfg.configData);
  const requestOptions = {
    url: tokenUrl,
    method: 'POST',
    auth: {
      username,
      password,
    },
    data,
  };
  const response = await this.request(requestOptions);
  if (response.data && response.data.access_token) {
    this.logger.info('Access token is received);
    return response.data;
  }
  throw new Error('The response does not contain access_token, please check your credentials or API');
}

Considering all of the above, the Token Code can be as follows:

async function run(msg, cfg, snapshot) {
    const addAuthenticationToRequestOptions = async function (requestOptions) {
        const accessToken = await this.getToken();
        requestOptions.headers.Authorization = `Bearer ${accessToken}`;
    };
    const getAccessToken = async function () {
        const { tokenUrl, username, password, data } = JSON.parse(this.cfg.configData);
        const requestOptions = {
            url: tokenUrl,
            method: 'POST',
            auth: {
                username,
                password,
            },
            data,
        };
        const response = await this.request(requestOptions);
        if (response.data && response.data.access_token) {
            this.logger.info('Access token is received);
            return response.data;
        }
        throw new Error('The response does not contain access_token, please check your credentials or API');
    };
    const body = { addAuthenticationToRequestOptions, getAccessToken };
    this.logger.info('Execution finished');
    return body;
}

In this case, configData field should be:

"{\"tokenUrl\":\"https://example.com/api/v2/client/tokens\",\"username\":\"username\",\"password\":\"password\",\"data\":\"data\"}"

Input Metadata description

URL

Path of the resource relative to the URL base. If there is no URL base, this should be treated as the full URL.

Method

HTTP Verb for the request.

HTTP headers

HTTP headers to attach to the request.

Request Body

Body of the request to send.

If Error Tolerance is Manual:
HTTP Codes to throw errors

An optional double array of HTTP response code ranges for throwing errors. The default is empty, []. Use a syntax that matches retry-axios. For example, [[400, 403], [405, 599]] would throw errors on all errors apart from 404.

Output Metadata description

Status Code

HTTP status code of the request

HTTP Headers

HTTP headers of the response

Response Body

JSON representation of the response body from the request