Working with secure API calls in Freshworks Apps

Overview

This wiki will get you introduced to the advanced feature of the app SDK called Request Method; this helps to make networking for Freshdesk apps easier and, much more importantly, secure. With this introductory, you’ll be able to perform any API calls securely from any apps built on Freshworks products.

To understand the Request Method and its usage on various request types, take some time to read any Freshworks product developer documentation on Request Method; as a reference, find Freshdesk’s documentation here.

Send a simple request

Firstly you need to have Freshworks CLI, a.k.a Freshworks Developer Kit (FDK), installed. For installation instructions, head over to the installation guide. You use the FDK’s advanced feature “Request Method” to perform a sample and simple API request at a very high level.

client.request.get("https://dog.ceo/api/breeds/list/all", options).then(
  function (data) {
    //handle "data"
    //"data" is a json string with status, headers, and response.
    console.log(data);
  },

  function (error) {
    //handle failure
    console.log("error:", error);
  }
);

The method delivers the parsed response, logging the value of data will return in JSON string with Status, Header, and Response. Taking care of the failure in request, the error handler helps to log down what went wrong. The snippet shows us how easy it is to perform a get request as it doesn’t need an API token, But when we need an API token to make a call, the following code snippet is an unpopular and unsecured way of making a request.

client.request
  .post("https://helloworld.freshdesk.com/api/v2/tickets", {
    headers: {
      Authorization: "Basic 23KJSDLJFXXXXXXXXKD",
    },
  })
  .then(
    function (data) {
      //handle "data"
      //"data" is a json string with status, headers, and response.
      console.log(data);
    },
    function (error) {
      //handle failure
      console.log("error:", error);
    }
  );

Send a simple but Secure request

From the last title, we additionally have Secure; in the same way, we’re going to add on and leverage a configuration feature from the developer platform called “Installation Parameters.” The FDK enables you to define and use parameters whose values app users can set when installing the app. These parameters are termed installation parameters or iparams, to know how to use them extensively, jump ahead to the installation parameters documentation and play along with Dynamic Installation pages tutorial.

Let’s learn to build a sample app on Freshservice on how we could leverage Installation parameters to perform API calls securely using the Request Method. With some minor changes, feel free to replicate the approach on other Freshworks Products as an exercise.
With this sample app, we are going to retrieve the Freshservice tickets data using API Key and log them in the console.

Set up the boilerplate

Considering you have the FDK installed,
Get into any of your development directories as we’re going to build it from scratch,

  1. Run the command fdk create and choose freshservice as a product
  2. Select your_first_app
  3. Open the manifest.json file and the whitelisting domain as shown below:
    "whitelisted-domains":[
       "https://*.freshservice.com"
    ]
    

You are now ready with the boilerplate and yet to configure the Installation parameters whose values can be set by the user when installing the application.

Configure Installation Parameters

Essentially, these are the necessary values that can be set via the iparams page to retrieve the tickets data.

  • Domain name
  • API Token

From the file structure, get into the config folder and update the iparams.json with the following snippet.

{
   "domain":{
      "display_name":"Freshservice Domain name",
      "type":"domain",
      "required":true,
      "type_attributes":{
         "product":"freshservice"
      }
   },
   "api_key":{
      "display_name":"Freshservice api key",
      "description":"freshservice API requires app calls to include API keys in all of their requests",
      "secure":true,
      "type":"text",
      "required":true
   }
}

The attribute secure under “api_key” is an important trait to be concentrated on, this ensures the encryption of the installation parameter data and stores securely in the cloud, marking it as secure sets the seal on hiding the parameter from regular iparams in frontend method and browser developer tools, this specific configuration will request the user on the installation page to provide the Domain name and the user’s API Key to fetch Tickets data further. The following screenshot is the out-turn installation page produced from the above configuration.

Note:

  • Secure iparams will also be available as plain text in the function argument for all the Serverless events since the environment runs in a secure cloud, others can not view them.
  • As per the guidelines from the platform, it is mandated for all the credentials and secret information in the iparams to be marked as secure.

List all Tickets data securely.

We are almost there, and just a single step away, the procedure is to make a GET Request to the Freshservice API endpoint https://<domain-name>.freshservice.com/api/v2/tickets with the domain name and the API Key which are securely fetched from Installation parameters wherein the user(you) installs after running the application.

Let’s update the code to perform the request and log the data in the console.

  1. Open app.js by navigating from the folders app to scripts.
  2. Replace the complete code with the following one; this is just to keep you aligned irrespective of future SDK changes.
document.onreadystatechange = function () {
  if (document.readyState === "interactive") renderApp();

  function renderApp() {
    var onInit = app.initialized();

    onInit
      .then(function getClient(_client) {
        window.client = _client;
        client.events.on("app.activated", listAllTickets);
      })
      .catch(handleErr);
  }
};

function listAllTickets() {
  var options = {
    headers: {
      Authorization: `Basic <%= encode(iparam.api_key) %>`, // substitution happens by platform
      "Content-Type": "application/json",
    },
  };
  client.iparams.get().then(function (iparams) {
    const URL = `https://${iparams.domain}.freshservice.com/api/v2/tickets`;
    client.request
      .get(URL, options)
      .then(function ({ response }) {
        console.log(response);
      })
      .catch(console.error);
  });
}

function handleErr(err = "None") {
  console.error(`Error occured. Details:`, err);
}

In the function listAllTickets(), the API Key in the Authorization header will be filled by fetching it from the iparams object; it is the same with fetching the domain name as well.

Run it

  1. Get back to the root directory and run the command fdk run
  2. Open the prompted URL to config the installation parameter by providing the Freshworks domain name and API Key, http://localhost:10001/custom_configs, to finish hit Install.
  3. As per the default configuration in the manifest.json file, the application is running at ticket_sidebar location, navigate to any of the tickets pages and append ?dev=true at the end, and reload. Example: https://.freshservice.com/helpdesk/tickets/1?dev=true

You’d now be able to find the application running in the ticket sidebar, view the app, and open the console from developer tools to find the fetched list of ticket details.

Note:
In the case of Serverless apps, feel free to use any HTTP Library with API Key in plain text in server.js; this will not affect the security of the applications and will not be visible to the user as it runs on a sandbox server in the cloud. It’s safe.

4 Likes

Awesome Wiki!!! Had a couple quick questions. In the freshservice FDK documentation we see this

In the above code we see image
If we are using the request method is it necessary and secure to use client.iparams.get() to retrieve the installed domain name. Or can we can continue to use it in this fashion as an example.
image
Just want to make sure that I am adhering to the security requirements and not exposing sensitive information :slight_smile:
Thank you!!!

4 Likes

@Zach, for what I understood from the Security updates to the platform - 19 May 2021, you can not use anymore the params marked as secure in the body or in the URL request. So if you mark the “iparam.freshservice_subdomain” as secure, you won’t be able to use with template substitution <%= iparam.freshservice_subdomain %>, nor get it from client.iparams.get(). You will need to declare the param without the secure flag - and in that case, you can get it from client.iparams.get() and interpolate in the URL request string https://${iparams.domain}.freshservice.com.

Tip: In some cases you need to prevent even the URL request from being exposed. So in these cases you can mark everything as secure and then make the request from the server side through Server Method Invocation, since every serverless method receive in the payload all the iparams.

4 Likes

Appreciate the clarification. What you are saying was my understanding as well. Just had me confused as the official documentation does not reflect this, seen in the screenshot I posted. @tejakummarikuntla here is a little fist-bump :fist_left: to encourage a change to the Freshservice Developer Documentation :laughing:. Making requests from our application is so vital to leveraging the power of the platform!!!

Thank you guys for your help!

3 Likes

Wow, @Zach, @samuelpares on the right track, thanks for bringing this up. We are yet to update the official documentation according to our latest security changes. Zach here’s my :fist_right: ;p

3 Likes