For as long as Salesforce has existed, there have always been requirements for external systems to communicate with the platform, whether that be for pushing data into Salesforce, extracting data, or initiating business processes from remote systems. In fact, the ability for Salesforce to seamlessly integrate with external systems has been integral to the platform’s philosophy since the launch of their APIs just a year after the company’s foundation (Lane, 2019). This commitment to integration is underscored by the platform’s “API First” approach cited throughout Salesforce documentation and Trailhead materials and is demonstrated through the company’s extensive Postman collection. Indeed, with over 200,000 forks, Salesforce boasts the most popular collection in the Postman API Network (Lin, 2022).
The secret sauce to all of this interconnectivity has, until now, been the Connected App. But with the Summer ‘24 Release, Salesforce has extended the capabilities of the next generation of connectivity and interoperability on the platform – External Client Apps. I’ve spent some time playing around with this new feature and in this article I’m going to recap the role of Connected Apps, the new External Client App, discuss some of the challenges and nuances customers (and particularly ISVs) have faced with Connected Apps and walk through the creation of a distributable External Client App. Let’s get stuck in…
Quick Recap: The Role of Connected Apps and External Client Apps
For System A to communicate with System B, System A needs a mechanism to safely and securely authenticate with System B. This is often likened to System A having a username and password for System B, but without having to share actual usernames and passwords across the internet and with different services.
Connected Apps and External Client Apps (ECAs) are responsible for creating and safeguarding this exchange of credentials for system-to-system communication on the Salesforce platform. Once a Connected App or an ECA is defined, it generates a Client ID and Client Secret, which can be used to retrieve an authorization code and, ultimately, an access token.
Using the resulting access token, developers can send messages to valid Salesforce endpoints from external systems for the purpose of creating or retrieving data, initiating Flows, firing Platform Events and more.
Ok… So What’s Wrong with Connected Apps?
Connected Apps have functioned well for years (decades?) and empowered customers and partners to endlessly integrate with the platform. But as the years and the platform have advanced, so too has the need for a Connected App “refresh,” if you’ll pardon the pun…
Globally Available
The most curious aspect of a Connected App is that, unlike any other metadata type I can think of, once defined, a Connected App is exposed across Salesforce’s entire global org infrastructure. That is to say that a Connected App in Org A can entirely support an authentication flow in Org B, without ever having to be created or installed in Org B. Salesforce openly states that this is contrary to a “Default Closed Security Posture,” but it also provides a somewhat confusing user experience, where one can freely authenticate against an org where the Connected App does not exist, but can then optionally “install” the app under the Connected Apps OAuth Usage page to manage that Connected App’s policies. A bit weird.
2GP Packaging
ISVs can avoid this user experience peculiarity if they add the Connected App to their managed package, but that’s where we hit our next snag. Connected Apps do not really support the latest packaging technology, 2GP. Instead, there’s a quirky workaround whereby a developer must first create a 1GP package with the same namespace as their 2GP and then reference the connected app from that 2GP app.
Development Slow Down
Next up, changes made to key attributes within the connected app can take up to 10 minutes to take effect. This is presumably due to those changes being replicated across Salesforce’s infrastructure, but it can be a bit of a pain when fiddling around in the early stages of app development. Pop the kettle on.
Single Callback URL for all Subscribers
As an Expert Product Development Outsourcer, that is, an organization that specializes in building distributable products on the Salesforce platform, which may have many, many subscribers, we’ve found this one hits hard for the ISV community. A Connected App is created with a single Callback URL which cannot be modified once installed in a subscriber org. This creates a challenge whereby an ISV that may have a multi-tenanted architecture, much like Salesforce’s own, is forced to stand up a centralized callback URL for the purpose of managing authentication between a distributed application with, for example, a different domain for each customer.
Spoiler alert: This challenge is, unfortunately, not (at least not yet), resolved by the introduction of ECAs and I can see why this could be challenging for Salesforce to overcome. But, indulge me for a moment, wouldn’t it be fantastic if an ISV could use the existing capabilities of the Subscriber Console or the Feature Management App, which both already have established connections between a PBO and subscriber orgs, through which the callback URL for their namespaced ECAs could be customized per subscriber. Alas, one can dream…
Lastly, in a recent Salesforce webinar, available in the Partner Community, the team outlined a few more challenges with Connected Apps that ECAs are able to resolve:
How are External Client Apps Different?
Firstly, ECAs entirely remove the concept of a globally defined app. When you define an ECA, you are required to specify whether the ECA is Local to the current org, or “Packaged,” signifying it will be distributed to other Salesforce instances. Unlike Connected Apps, a Local ECA cannot be used to authenticate into other orgs and a Packaged ECA cannot be used to authenticate into orgs within which it is not installed.
It’s, therefore, essential that ECAs are defined in long-lived environments and not in trial or scratch orgs. Salesforce has our backs there, though, as scratch orgs do not permit the creation of ECAs. To verify this, I gave it a go and received the following error:
“The Org Scoped External Client App must be in the format DeveloperOrganizationId:ExternalClientAppDeveloperName”. It’s not quite the friendly error message I might have expected, but it did the job and prevented me from creating the ECA in a scratch org.
For ISVs, we’d recommend creating the ECA in your activated Partner Business Org, so you can be sure this isn’t going to disappear on you. Who knows what pain awaits the ISV who manages to find a way to have the org hosting their ECAs purged. Let’s not find out.
Here’s what an ECA looks like once we’ve created it. A lot of the content is familiar if you’ve spent much time with Connected Apps, but here we can see a clean separation of developer-aligned settings and admin-aligned policies. More on that shortly…
Once the “Packaged” ECA has been created inside the appropriate org, we can pull this metadata down into our local environment. To get everything up and running, we need two pieces of metadata for each ECA:
N.B. Since we have to pull these from our PBO, I recommend the use of the handy –metadata parameter to focus on just these 2 metadata types to prevent pulling unwanted customizations from your PBO into your local project.
Here’s a great diagram from the Salesforce ISV Technology Advisors and Platform Experts team, further emphasizing how this metadata enables a clean separation between static, protected developer settings and customizable admin-defined policies:
Once we have our metadata pulled locally, we can spin up a scratch org, get the metadata pushed in* and start developing against the ECA as if it were installed in a customer environment. Again, this is another big win for ECAs vs. Connected Apps, which were challenging to develop against within a scratch org context.
*For the time being, we have to first open the scratch org, enable ECAs in Setup and then push the metadata in. This also means we need to skip validation checks in the packaging process, since the hidden “build org” used for packaging won’t have this feature enabled. I’m told this will be enabled by default in the next release and therefore no longer an issue.
Once we have our app developed, we can go through the usual process of packaging up our metadata and installing it in an org. Here’s what the same “Aquiva Labs Demo” ECA looks like once it’s installed, note that subscriber admins are free to update the Policies tab as required, but are unable to modify settings or see OAuth settings. A much improved user interface when compared with Connected Apps.
Additionally, it’s worth noting that, because of Connected Apps’ global nature, updates to the central app used to be propagated across all orgs. Given this global approach has been removed, any changes to your ECA will need to be pulled down from your PBO, packaged up in a subsequent package version and distributed to subscribers. On the flip side, we no longer have to wait 10 minutes for our changes; my experience suggests that’s immediate, presumably because that propagation no longer needs to occur.
From a development and integration point of view, you won’t see much change. I was able to authenticate with an org and start communicating between systems in much the same way as we could with a Connected App. I first took advantage of the Postman collection previously mentioned, then had a bit of fun with Apex, LWC and CMTs, using my new ECA-powered connection to send messages from one org to another. I used refresh tokens, revoked access and re-authorized myself exactly as you’d expect, and I tried this out with the somewhat new Integration User License with no issues. You can see this PoC on my GitHub profile here and a quick demo video below where the left org authenticates with an ECA in the right org and is then able to send a message:
Parting Thoughts
External Client Apps are a nice leap forward for authorization on the platform. They overcome both technical and user experience challenges left by Connected Apps and give customers and ISVs a fully supported mechanism for development and packaging. I still think there’s an opportunity to make this even better by providing a route to modify the callback URL per subscriber, but let’s see what the future holds. In the meantime, it’s nice to see investment in the fundamentals of the platform, as well as the shiny new products that often lap up much of the hype.
As the demo above shows, ECAs are available and functioning today, so Salesforce encourages their adoption. What’s more, they’ve stated that ECAs are the next generation of Connected Apps, and thus we can assume this is where future investment and features will be built out. I’ll be taking an “ECAs-first” approach to integration projects in the future, but we should call out that there’s not yet feature parity. Best to look at the official Salesforce docs for updates on this. As of the time of writing, Salesforce provides a clear table in their documentation on what ECAs support and what’s not yet available.
If you’re looking for help integrating an external application with Salesforce and are looking for help with product development or implementation, as a Summit SI and Expert PDO, Aquiva Labs are here to help. Reach out to us below!
Written by:
Michael Holt
Head Architect, PDO Practice
References
Lane, K. (2019). Intro to APIs: History of APIs. Postman.
https://blog.postman.com/intro-to-apis-history-of-apis/
Lin, J. (2022). The most popular collection in the Postman API Network. Postman. https://blog.postman.com/the-most-popular-collection-in-the-postman-api-network/