Getting Started with Application Channels
This tutorial guides you through the process of creating an application channel in Front. Application channels allow you to add communication channels to Front, such as SMS or social media messengers, to increase the communication methods that Front users have access to. The channel in this tutorial will be able to create and receive outbound and inbound messages from a generic service, and will be able to sync those messages to Front, with just a little code modification on your end. Some of the capabilities of the channel described in this tutorial include:
- Authorizing Front users connecting with your channel.
- Instantiating a new channel.
- Processing new message events that occur in Front so they are handled appropriately in the external system.
- Syncing message events that occur in the external channel system so they are appropriately displayed in Front.
The tutorial is based on a channel template that you can use as a starter project for any channel integration. This starter project is meant to kickstart your development of a fully-fledged channel integration that you can make available to all Front customers. By using the starter project as a code template and reading this tutorial for reference, you should be able to save development time and learn the key concepts necessary for building successful channel integrations with Front.
Quickstart
If you prefer to get the code in this tutorial up and running quickly prior to reading through the rest of this tutorial, refer to the Readme in our GitHub repository for condensed instructions.
Prerequisites
- To set up a channel as described in this tutorial, you will need a set of channel credentials. You can obtain these credentials by first creating an app, then adding a channel type feature to the app, and then noting the App UID and the App secret listed in the Basic information tab of the app.
- Adding a channel type feature to an app in Front involves specifying a webhook URL where your channel will listen for Front updates. You then specify this value in the configuration section of the tutorial as the
callbackHostname
.
- Adding a channel type feature to an app in Front involves specifying a webhook URL where your channel will listen for Front updates. You then specify this value in the configuration section of the tutorial as the
- Install NodeJS to run the code in this project.
Source code
You can view the source code for this project on GitHub.
You must make changes to the template code to make it production ready
The code is written with the goal of demonstrating how to implement a channel in Front in as simple a way as possible. As such, it is not meant as production-grade code, and should not be used as such. It is only a starter project.
- In order to minimize complexity and maximize the educational value of the project, important security and authentication steps have been simplified.
- The full logic for handling channel messages outside of Front has also been omitted.
- When implementing a channel for a real world use case, you should expand upon the basic framework provided in this tutorial to ensure your code meets security standards, handles a wide range of error scenarios, and includes message handling logic specific to the channel you are implementing.
However, aside from these specific areas, the project provides a strong base for developing channel integrations with Front, and can be used to streamline your development.
The project uses JavaScript as its programming language, and specifically makes use of the following frameworks:
You do not need to be an expert in these frameworks to make use of this tutorial. The tutorial will explain the key components of the project architecture. With an understanding of the architecture in this project, you can adapt the code to the programming language of your choice.
Step 1: Set up the project
In this step, you clone the project from GitHub and install the project dependencies.
- Clone the partner-channel-template repo available on GitHub.
- In your terminal, change directories into the partner-channel-template directory that you cloned.
- Run
npm install --global yarn
to install the Yarn package manager. - Run
yarn install
to install the project dependencies.
Step 2: Configure the server file
The src/server.ts file configures the Front channel credentials and establishes a server to handle channel requests.
- Open src/server.ts for editing.
- Replace the
frontID
andfrontSecret
values with the App UID and App secret you obtained from the Basic information tab for your app.
Use a secure method for retrieving channel credentials
In a production scenario, obtain the channel configuration values from a secure environment file or variable outside of the server.ts file. This tutorial hard codes the values into the file for the sake of simplicity, but this is not a safe practice for your production Front channel implementation.
export const frontId = 'yourFrontId';
export const frontSecret = 'shhhhhhhhh';
- Replace the
callbackHostname
value with the webhook URL where your server will run. For purposes of development, you can set up a local server using a tool like ngrok. When you are ready to deploy your channel to production, you can replace the development URL with your production URL. If you need to, adjust the default server port to the one you are using.
export const callbackHostname = 'https://your-ngrok-hostnmae.ngrok.io';
export const serverPort = '3000';
- Save the file.
- Familiarize yourself with the rest of the code in the src/server.ts file.
- The code exports a randomString function for use in other parts of the project.
Update the randomString function for production purposes
This tutorial uses random strings to generate webhook IDs, message and conversation identifiers, and access tokens. In a production implementation, replace the
randomString
function with functions that generate these values securely and in a way that is appropriate for the channel you are integrating with.
- The code uses ExpressJS to set up middleware for processing requests and responses on the webhook server.
- The middleware parses URL-encoded JSON requests, including rich objects and arrays, so that the request values are accessible through JavaScript.
- The middleware routes requests using the routing logic configured in the src/routes.ts file.
export function randomString(length: number): string {
return randomBytes(Math.floor(length / 2)).toString('hex');
}
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(ChannelRouter);
app.listen(serverPort, () => {
console.log(`Express server listening on port ${serverPort}`);
});
Step 3: Run the channel code
Now that you have configured the channel settings in the project, you can run the code.
- Open a terminal window.
- Run your webhook server. During development, you can use a tool like ngrok to run a local server that listens for events on port 3000 (or the port of your choice) by running
ngrok http 3000
. For the production version of your channel, ensure the webhook server is hosted on a public URL. - Ensure the callbackHostname value in the server.ts file matches the URL of the webhook server.
- Open a second terminal window.
- In the partner-channel-template directory, run
yarn start
to run the project code.
With these two terminals running, your channel integration will be able to listen to requests from Front on the configured port and route the requests appropriately to different sections of application logic.
Step 4: Add your channel in Front
With your code running, you are ready to add your channel in Front. Configuring your channel in Front adds an inbox (similar to an email inbox) in Front that is connected to an instance of your channel. Note that this steps depends on creating an app with a channel type feature as described in the Prerequisites section.
During development, you will be able to add your channel to the Front instance in which you created your app. After your integration is complete, Front can make it available to all Front customers if you so choose.
- In Front, click Settings > Personal > Inboxes.
- Click Add an individual inbox to set up a new inbox.
- Follow the prompts to set up the inbox. In the Channels section, select your channel from the available options. The channel name and description should match what you specified in the app that contains your channel type feature.
- Supply the required authentication for your channel.
Ensure the server is running
During this step, Front sends an authorization request to your channel. If the request fails or your server is not running to receive it, then setting up the channel will fail. Refer to the Instantiating a new channel section to learn about the code that handles the initial authorization request.
- Finish configuring the inbox.
- Return to your main workspace view in Front.
- Click the new inbox that you just set up. This inbox is connected to an instance of your channel.
When you send outbound messages through this inbox, or import messages into it, Front sends updates to the webhook specified by your channel code so that your integration can process them. You can also use the Channel API to sync inbound and outbound messages from your channel to Front. Continue reading the rest of the tutorial to learn how the channel template code works in detail.
Note the action items in this tutorial
Make sure to note the Action items in the following sections of this tutorial. These items describe how to modify the code for use in a production channel integration.
Step 5: Familiarize yourself with the routes file to learn the application logic
The src/routes.ts file controls how requests from Front to your channel are processed. The file uses the routing functionality of ExpressJS to control how your channel integration responds to requests sent from Front.
Handling the OAuth flow
Front recommends that application channels implement OAuth 2.0 to authorize channel users. When a Front user connects to a channel configured with OAuth, Front sends authorization requests to your channel.
These routes handle the OAuth requests by:
- Redirecting the user to the specified OAuth redirect URI after successful authentication.
- Providing an authorization code in the redirect URI for use in requesting an access token.
- Providing an access token and refresh token when requested by Front.
Action item
For the sake of simplicity, the tutorial code does not implement a real OAuth flow. Instead, it supplies random strings for the OAuth code and tokens. To complete your channel integration, add the logic for connecting with your authorization server within these routes.
Front API tokens are an alternative to OAuth
Front recommends that your application channel implement OAuth for the convenience of the end user, but you can also use the API token authentication method and omit these OAuth routes. To learn more about the available authentication methods for application channels, refer to the Fundamentals of Application Channels topic.
Instantiating a new channel
When a Front user connects your channel to an inbox, Front posts an authorization request to your channel.
This route handles the request by:
- Checking that it is an authorization request. If it isnβt, an error is sent to Front (note that the value of the
message
field in the error response is exposed to the Front user). - Responding with status code
200
andtype:'success'
- Responding with a unique URL
webhook_url
for the channel to make requests to.
Action item
In the tutorial code, the URL generates a webhook ID based on a random string. In your channel implementation, implement the appropriate logic for supplying a unique webhook identifier from the external system. Front saves the webhook ID for each instance of your channel that a user connects in Front. Subsequent requests for the channel instance are sent to the same webhook URL, which can be useful for organizing requests in your external system.
- Retrieving the
channel_id
property.
Action item
When Front sends the authorization request, it also includes a
channel_id
property. This value is different from the Front ID and secret credentials supplied for your channel from the Basic information tab. You need thechannel_id
if you want to sync inbound or outbound messages made in the external channel into Front. To sync those messages, your integration will need to call the Channel API, which requires thechannel_id
to identify which channel in Front to send the messages to. The tutorial code does not demonstrate how to retrieve and store the state of thechannel_id
, so this is something that you must add in a production channel integration if you wish to sync external messages from the channel into Front.
Handling new message events from Front
This route processes new message events that occur in Front so they are handled appropriately in the external system. The message events that correspond to this route include:
- A new outbound message sent by a Front user that has the channel connected.
- A new outbound auto-reply message sent from the channel in Front.
- A new message imported webhook notification is sent from Front.
In all these situations, Front posts a request to the webhook URL your channel specified when it was instantiated in the previous route. These outbound messages and imported message notifications are events that originate in Front and are therefore messages that the external channel does not know about.
This route handles this type of request by:
- Checking that the message is of type
message
,message_autoreply
, ormessage_imported
. Front recommends this best practice of checking for message type to gracefully handle different types of messages and to future proof your channel integration in case new message types are added in the future. - Responding with an error if the message is not the correct type. Note that the value of the
message
field in the error displays to the Front user. - If the message is of the correct type, responding with status code
200
andtype: 'success'
- Responding with an
external_id
for the message and anexternal_conversation_id
for the conversation that the message belongs to in the external system.
Action item
The tutorial code generates random strings for these IDs, but your channel integration should add the appropriate logic for supplying the proper message and conversation identifiers from the external system.
- Responding to different types of messages (normal messages, autoreplies, message import notifications) with different logic.
Action item
The tutorial code outlines how to respond when Front message events are sent to the channel. However, the code does not supply logic for what to do in the external channel system when messages are received from Front. In your channel integration, add logic for how to handle the messages received from Front in the external system. For example, when an outbound message is created in Front, this outbound message should be recreated in the external channel system, and the identifiers of the resulting conversation or message should be returned in the response to Front. If there are delays or errors in the external system, appropriate error handling should be in place to respond to Front and retry the operation later.
Deleting an instance of a channel
When a Front user deletes an instance of your channel from an inbox, Front sends your channel integration a delete request.
This route handles the request by:
- Checking that the request is a DELETE type. If it isnβt, an error is sent to Front (note that the value of the
message
field in the error response is exposed to the Front user). - Responding with a status code of
200
if the request is received successfully.
Action item
The tutorial code provides a response to the deletion request, but does not supply any logic for handling the request in the external system. Add the missing logic in your channel integration so that the event representing a user removing the channel from their Front inbox is appropriately reflected in the external system. This could involve triggering notifications about the disconnection or initiating downstream tasks in the external channel system.
Verifying that requests are coming from Front
For security purposes, your channel integration should verify that all requests made to your webhook server are coming from Front. The tutorial code executes the verifyFrontRequest method for all routes in the application. This method contains the following logic to verify that the requests are authentic:
- Extracts the timestamp supplied in the request header.
- Creates a SHA-256 signature based on the timestamp, request body, and the secret associated with your channel.
Use a secure method for retrieving channel credentials
In a production implementation, you should obtain the secret value from an environment file rather than hard coding it into the src/server.ts file as shown in the tutorial.
- Checks to see whether the signature generated matches the
x-front-signature
supplied in the header. If the signatures do not match, your integration should return a400
response error and assume the request is not coming from Front.
The following partial code snippet displays the function logic. Refer to the full file for necessary imports.
function verifyFrontRequest(req: Request, res: Response, next: NextFunction) {
const timestamp = req.headers['x-front-request-timestamp'];
const rawBody = JSON.stringify(req.body);
const baseString = `${timestamp}:${rawBody}`;
const hmac = createHmac('sha256', frontSecret)
.update(baseString)
.digest('base64');
if (hmac !== req.headers['x-front-signature']) {
return res.send(400).json({ type: 'bad_request', message: 'Signature not verified' });
}
next();
}
Step 6: Familiarize yourself with the Front Channel API connector file to understand how to sync external message events into Front
The src/front_connector.ts file syncs message events that occur in the external channel system so they are appropriately displayed in Front.
This file provides methods that use the Channel API to sync inbound and outbound messages from the external channel into Front. Using these methods, your channel integration can update the Front inbox so that it remains in sync with the external channel system. In this way, Front users can see inbound and outbound messages that have occurred in the external channel system and that Front otherwise does not know about.
Call the methods in this file or use Postman to test the Channel API endpoints
The tutorial code does not call the methods defined in this file. You can modify the code to do so, or use an API testing client like Postman to call the API directly for testing purposes. Whether you call the methods in the code or make the API requests through a testing client, you will see inbound and outbound messages appear in the Front inbox in which you connected the instance of your application channel. You can use our Channel API Postman collection to facilitate your testing for this section of the channel integration.
Channel ID
When Front sends the initial authorization request for your channel, it also includes a channel_id
property. This value is different from the Front ID and secret credentials supplied for your channel. You need the channel_id
to make calls to the Channel API, which allows you to sync inbound and outbound messages from the channel into Front.
Action item
Refer to the Instantiating a new channel section to learn how to retrieve the
channel_id
value. Store this value and make it accessible within the front_connector.ts file. This value allows your integration to call the Channel API and sync messages that occur in the external channel into Front.
TypeScript Interfaces for the Channel API requests
The front_connector.ts file defines TypeScript interfaces for the Channel API message objects.
Sync inbound message
This method syncs inbound messages that occur in the external channel system using the Sync inbound message endpoint. For example, a recipient has connected the channel integration to an external system such as Instagram or Slack. The recipient receives a message on the external application (e.g., Instagram) rather than Front. In this situation, Front doesnβt know about the new message received until you use the Sync Inbound Message endpoint. The result is Front updating its UI to represent a new message sent to the channel inbox.
The method uses the API request helper functions to assemble the endpoint URL and headers as appropriate, depending on what type of API call is needed and whether the payload includes attachments.
Action item
Add logic for calling this method whenever an inbound message should be synced from your channel to Front.
Sync outbound message
This method syncs outbound messages that occur in the external channel system using the Sync outbound message endpoint. For example, a recipient has connected the channel integration to an external system such as Instagram or Slack. The recipient sends a message on the external application (e.g., Instagram) rather than Front. In this situation, Front doesnβt know about the new outbound message until you use the Sync Outbound Message endpoint. The result is Front updating its UI to represent a new message sent from the channel inbox.
The method uses the API request helper functions to assemble the endpoint URL and headers as appropriate, depending on what type of API call is needed and whether the payload includes attachments.
Action item
Add logic for calling this method whenever an outbound message should be synced from your channel to Front.
Build the JSON web token
The buildToken method creates a JSON web token that is used for authenticating the Channel API requests. The token is sent in a header as Authorization: Bearer <token value>
. This method contains the following logic:
- Establishes a Unix timestamp ten seconds from the current moment. The additional ten seconds are added to set an expiration for the token within that window of time. This extra security measure prevents a token from being reused beyond the initial ten second window, even if it is successfully intercepted by an attacker.
- Creates a JWT payload with the channel ID, Front ID, and a random string.
Use a secure method for retrieving channel credentials
In a production implementation of a application channel, these values should be securely retrieved from an environment file rather than hard coded into the server.ts file.
- Signs the token with the Front secret. Note that in a production implementation of a channel, this value should be securely retrieved from an environment file rather than hard coded into the server.ts file.
static buildToken(channelId: string) {
const signature = frontSecret;
const exp = moment.utc(Date.now()).add('10', 'seconds').unix();
const payload = {
iss: frontId,
jti: randomString(8),
sub: channelId,
exp
};
return jwt.sign(payload, signature);
}
All done!
Congratulations! You just set up a code template for building channel integrations with Front. This template handles instantiating a new channel, authorizing Front users trying to connect with your channel, processing new message events that occur in Front, and syncing message events that occur in the external channel system back into Front.
You can use this template to build application channel integrations and make them available to all Front customers or just your own company.
Now that you are familiar with the basics of building application channels, refer to the following resources to complete your understanding and facilitate your development:
- Channel API reference
- Fundamentals of Application Channels
- Tools for developing application channel integrations
- FAQ about application channels
Updated over 1 year ago