Secure third-party libraries in your managed package
twitter social iconlinkedin social iconfacebook social icon

Secure third-party libraries in your managed package

By: Hugo van Krimpen

You are planning to release your very first application to the Salesforce AppExchange. You’ve had a great idea to visualize data by using a third party Javascript library which allows for easy creation of graphs and charts. After implementing the library using loadScript and loadStyle in your Lightning Web Component and building your application around it, you compile your code into a managed package and submit it to the Salesforce security review.

But, to your disappointment, the security review fails because of an insecure implementation of your third-party library. The response is that the third-party library performs DOM manipulation and might therefore modify your environment in unintended or even malicious ways. Or worse: the library might be able to read your data in the LWC and pass it to a remote server.

As of recently, we’ve faced this response from Salesforce more and more: we specifically need to implement our third-party applications in managed packages in a separate container so it will not have access to other Salesforce components. In order to prevent these security issues and pass the security review, they ask to implement the third-party library using lightning:container.

But what is a lightning container? In this blog, we give you a detailed explanation. However, to get a complete understanding, you need to understand Lightning Locker first.

Lightning Locker

Lightning Locker is an architectural concept that limits how components in one namespace can access components or data in another namespace. Without the Lightning Locker, a developer would be able to access and edit everything on the org. In the worst-case scenario, third-party applications would even be able to read, store and share your data!

Lightning Locker is enabled by default for all components using API version 40 or higher. Components with API version 39 or lower do not implement the Lightning Locker and are therefore less secure and not compliant with the latest Salesforce security standards. A component using an API higher than version 40 that is not Lightning Locker compliant will not function properly or throw errors in your browser's console. It applies to most modern Salesforce functionalities, like aura components, applications, lightning web components and flows.

Lightning Locker automatically enforces most of the web development security principles. However, it also changes or disables some of the more commonly used Javascript elements to achieve this. The most notable are:

  • The use of global objects is restricted by hiding objects or by wrapping them in a secure version of the object. Effectively this means that not all standard javascript objects are available, and many of the standard ones are redirected to a “Secure Version” with limited functionality. E.g.: calling window or document is calling SecureWindow and SecureDocument respectively.

    Want to know which objects are available? See the official documentation.

  • A component can only traverse the DOM and access elements created by a component in the same namespace. Accessing the DOM < c-child-element > is allowed as it is in the same namespace. Accessing the DOM of < lightning-button > is not allowed, as that component resides in the lightning namespace.

  • Lightning Locker enforces Javascript strict mode. Any unsafe actions in your code, like assigning a value to a read-only property, will throw an error.

Please see the Salesforce developer documentation for a full list of restrictions.

Lightning Container

So how does this relate to a lightning container? A lightning container (< lightning:container >) is an aura component that enforces a static resource to be loaded in a separated Lightning Locker. Anything in this container is guaranteed to be unable to access anything outside the container. Only data specifically passed to the container can be accessed by anything inside it. This way the developer (and in the bigger picture: the end user) is ensured only necessary data is passed to the third-party library, reducing the risk of malicious attacks.

A lightning container takes a static resource and loads it in an iFrame. This static component can be anything: a Visualforce Page, Aura Component, Lightning Web Component, or a website using a third-party library React, AngularJS or D3.

Note: the resource still needs to adhere to most of the Salesforce guidelines! For example: Javascript is still not allowed to be inline in the html.

Once the container is loaded, a Salesforce developed module allows for messaging between the aura component and the contents of the container. Using this messaging service, you can pass data to the container or pass data from the container back to your component.

Lightning Container Example

Sending and receiving a message on the aura side is relatively easy.



Sending and receiving messages in the container is a bit harder. Salesforce requires you to download their lightning-container module using node.js and add it to the application. Alternatively, you can create a lightning-container.js file in your container code and add the following code to achieve the same:

Note: LCC.onlineSupport implements more than the two functions described above. E.g. it also contains a function to directly call an AuraEnabled apex class from within the container. For our scenario, we decided not to include these and go with a messaging system instead.

In your application, you can now import the LCM module. E.g. in a LWC resource, simply add the following to your import statements.

import LCM from './lightning-container.js'

And finally register handler functions for the messaging events:

You are now completely set to message back and forth between your aura component and your lightning container. Pass the data you want your container to show using your third-party library and have it handled it in the correct way.

Recap & Discussion

To sum up, Lightning Locker is a great architectural decision to ensure separation of concerns between different components in your application. It ensures that only the data you actually want to pass to a component is accessible to it and only functionality registered as global will be accessible to others. Lightning container is an extra implementation layer around the Lightning Locker. It allows the developer to develop an application separated from Salesforce. Ultimately, this application can be integrated with Salesforce using the messaging service, ensuring the two components can only communicate using whatever has been implemented.

Unfortunately, lightning:container is an aura-only component and does not yet exist in the LWC space. Therefore, anyone who actively develops using LWC needs to find a way to implement an aura component in their application and have it react to the already existing LWC source. We had a similar challenge and decided to use a pubsub framework to send messages to the aura component, which in its turn would interact with the application in the lightning:container. Suboptimal to call it the least, but it is the most secure (and required) method of implementing this.

Still some lingering questions? Don’t hesitate to contact me.

About the author

Hugo van Krimpen has over 4 years experience in the Salesforce consultancy and programming environment. The last 2 years he has been researching new Salesforce grounds working for Appsolutely. He is always looking for the new and next gadget or tool. This team player is helping our customers with finding the right solution.

Want to know what Appsolutely can do for your AppExchange App Development or read more technical blogs?


Share this article:
twitter social iconfacebook social iconlinkedin social icon

divider graphic


Product customizability and Overridable flows: Giving the controls to the customer
September 20, 2022

Product customizability and Overridable flows: Giving the controls to the customer

By: Hugo van Krimpen When developing Salesforce products for the AppExchange, we regularly face requ...

Hugo van Krimpen
By Hugo van Krimpen
Partner Event: Future-Proof Service Operations 2022
September 4, 2022

Partner Event: Future-Proof Service Operations 2022

Future-Proof Service Operations How to extend your service operations to sales, marketing, and beyon...

Luuk Timmermans
By Luuk Timmermans
Why you should stop just creating code!
August 10, 2022

Why you should stop just creating code!

By: Rodrigo Dantas Deep dive on Software Best Practices, and what we saw at TDX22 that backs up this ...

Rodrigo Dantas
By Rodrigo Dantas