Travis Cucore

Avoiding Salesforce Entitlements With MQTT

In this post, we'll dive into a practical solution for avoiding entitlement costs associated with Platform Events on the Salesforce platform with the added benefit of improving your ability to integrate while keeping the cost of doing so low or free.

But Why?

Our mission? To reduce "swivel chair" maneuvers for customer service agents through an integration between Ring Central (a reseller of Nice 'n Contact) by centralizing commonly referenced data in one place at the start of the customer interaction with an agent.

We initially proposed an all OOTB solution leveraged the CRUD, and Platform Event APIs with a little quark of rollup summary fields paired with a hidden Lightning Web Component to trigger an agent's screen to open a new tab with caller information from their Salesforce instance. At the time, their agents needed to traverse many records before a customer call could be productive.

Unfortunately, reliance on Salesforce Platform Events would have come with an entitlement cost over and above what the client was willing to pay for. This is why we stepped outside the box.... This is why we had to go off platform.

A Trip Down Memmory Lane

As fate would have it, my college senior design project was an IoT platform based on the MQTT protocol. I called it edge-net. I built a cross platform app using xamarin forms, and rolled a MQTT client for the embedded portion using c/c++ on an ARM dev board I got from digikey (no, it was not an Arduino). Superfluous details aside, the client didn't need bi-directional communication, and I was confident an MQTT broker service would do the trick.

We would use the AWS IoT Core service, Paho-MQTT node client, some Apex, and a couple of Lightning Web Components.

What's MQTT?

MQTT is a protocol (Message Queueing Telemetry Transport) that features near sync or async communcation. At the time of writing, the latest version (MQTT 5) also supported a backhaul topic, which makes closed loop communication less expensive when latency is not a consideration or closed-loop async communication is unavoidable.

Put simply, MQTT is a protocol establishing the rules for implementing a publish/subscribe eventing service organized by topics.

With MQTT, the server and client are known as broker and publisher/subscriber respectively.

What's a Broker?

Brokers are responsible for making sure messages are delivered to clients subscribed to the topic they were published to according the the QoS set by the publisher. We used QoS=0 (Fire and Forget) which just means the broker will only deliver to subscribed clients that are online at the time the message was published.

The Revised Solution

The solution was to have Ring Central publish to a topic on an MQTT broker (AWS IoT Core). This client would likely never break out of the free tier given projected usage, and they were already AWS customers, so we didn't have any friction related to onboarding a new vendor to the client.

On the other side would be a Lightning Web Component (LWC) sitting in the agents Service Console subscribed to the same topic for that agent. When Ring Central published an event, the Lightning Web Component would pick it up as a subscriber, and open a new tab with the relivent caller information already loaded for the agent. At least that's it in a nutshell. The pattern is more important than the implementation for the purpose of this post.

I wanted to use the AWS SDK because first party libraries are usually the best way to go, but the node implementation was not locker complient. If the client had been on Lighting Web Security instead of Locker, we could have used the AWS IoT Core SDK.

Authenticating With AWS

The next challenge was in figuring out authentication. We needed to establish a websocket with the AWS IoT Core broker service, but we didn't want to (and you shouldn't) let private keys become discoverable in the browser. We couldn't use Named Credentials due to how Salesforce prevents the auth token in the response from making it back to Apex.

To solve for this, we stored the information needed to authenticate in Salesforce securely. When we needed to authenticate, we built the connection string for the MQTT client in Apex returning only what was needed to establish a websocket with the AWS IoT Core broker to the Lightning Web Component running in the agents Service Console.

You might be wondering what's to stop anyone from taking that connection string and hijacking the connection. The answer is, they could. But, they'd have to have access to the browser for that to happen, and if that were the case, I'd be worried about an aweful lot of other things. They'd also just boot the agent off which would cause their connection to retry thereby booting the hijacker off. We ensured only a single connection per agent was possible by generating topics from unique identifiers at runtime.

Ring Central could not establish a websocket, or compile a connection string, so we used an AWS Lambda funtion to authenticate and interacted with the broker independently from there.

The Outcome

The client ended up with a highly efficient, scalable, and extensible pub/sub network. When the agent picked up a call in Ring Central, a message was published to a topic specific to the agent for which an MQTT client running in the agent's browser was registered as a subscriber.

That subscriber processed the payload, found candiate matches for the caller, popped that information on screen for the agent and provided a means of selecting the correct candidate from a list and redirecting the tab to that customers information in service console.

The Takeaway

It is in Salesforce's best interest to build technoligies that keep you engaged with their products. That doesn't mean you have to use them, or that they are the best choice for your business application or budget. In this case, we were able to save our client money while giving them another option for distributing event driven communication using a publish/subscribe pattern enabled by the MQTT protocol.

You might have to go a bit mad to get it right. I probably spent more time than I should have believing I was doing something wrong with the AWS SDK before our TA came to me with PAHO MQTT to try. But, I've found saving people money generally makes them happy.