Hey @J805,
We can appreciate your original post as it highlights the security implications of having āhiddenā elements on your page for internal purposes. Numerous Bubblers have employed the strategy of using hidden inputs for calculations, repeating groups for queries and things of the like which are not the most secure nor most efficient. However, whatās more troubling is the misinformation weāre seeing above on plugin security. Seeing a couple of our plugins were mentioned above in addition to a fundamental misunderstanding of API calls, we took the time to shed some light on API basics and Bubbleās options for its plugin developers in an effort to benefit the community.
Fundamentals
API Calls
Interacting with a server/vendor for information usually involves an API call; you request some information from a location, you include an API key to identify who you are, you get a response. With the modern web standard, executing API calls is a must not just to request data from other services (Stripe, Google, etc.) but sometimes for your own application. For example, your frontend (also a client) could request information from your backend (as a server) such a userās profile information or whether theyāre even authenticated. The web is a network of servers talking to one another which means one party is requesting information from another who may itself be requesting and returning information, making API calls a facet of web development that every developer should be knowledgeable about.
API Location
API Calls are not exclusive to the client or server, and you decide where the API call must happen as the developer. If youāre accessing your own backend, thereās no way around exposing certain information to the user on the frontend even if thatās a token; take a stroll through your browserās Network tab to explore the type of information Airbnb, Uber, and Stripe send their own server when you use their frontends. See @vini_brito shortās and sweet comment above as well.
Your userās browser is making the API call to wherever your backend is accessible, and your backend could very well be executing API calls on its own to get what it needs. Most developers would understand the implications of making API calls to sensitive locations on the client, and thus would very likely build backends that run those API calls instead. Bubble offers the same extensibility with things like backend workflows, as you can easily take API actions from your frontend workflows and asynchronously run them on the backend. The decision lands on the developer as to where to execute an API call, and thereās more than just security and performance to consider.
API Visibility
With the right tools and motive, almost any interface channel can be intercepted. With the few large-scale infiltrations of enterprises highlighted this year alone, everyone is aware security is no laughing matter. One way of preventing a malicious party from comprising any system is lack of visibility, which is a strong argument for making API calls on the server again. Any API call (not just those made from a browser) will not know what other API calls, queries, etc. the destination server will make, as the client you just want what youāve asked for. The same way you request a retail store employee to find you an item from the stockroom: you donāt have permission to enter and rummage through the racks yourself but the employee does, you donāt know anything about the processes happening, so you just wait until they return and parse the result.
Plugin Security
Bubble allows the plugin developer to decide which keys can be exposed to the client and which keys cannot. As we know, the client is generally considered unsafe in the context of working with and exposing sensitive data while the server is more secure. Separating data across both the frontend and backend may make your development more challenging, but thatās a consideration of numerous factors including and beyond security. Bubble offers plugin developers certain types of fields to aid with the accessibility of information which is worth evaluating.
Field Types
Seeing the fields in your Bubble editor after installing a plugin can certainly make you reflect whether or not they are all required. When developing API actions (not JS actions) for plugins, the structure of the call may require some field values that the developer is knowledgable of but perhaps not their users. There are also cases where keys are required to access an API, on top of the formatting of the call itself to be compliant with what the destination server requires. Bubble solves some of the knowledge-gap and general UX problems of API actions with field types.
Here are Bubbleās own words on field types as shared in the Bubble manual:
-
Public parameters will be modified by the user at the call level (thatās for instance a term for query API call).
-
Hidden parameters are for the plugin builder, and wonāt be exposed to the user that uses the plugin. For instance, it can be an encoding type, etc.
-
Secret parameters are good for keys, etc. Users will enter these in the Plugins Tab of the editor.
The field types are determined by the developer based on what they require from their pluginās users. A common example is the Content-Type header of an API call; most users would not know what that is or what the valid value would be, so the plugin developer may choose to set the value to application/json, application/x-www-form-urlencoded, etc. and mark the whole field as āHiddenā so their plugin users donāt have to see or deal with it at all. If they wanted to expose it to their user in the Plugins tab, theyād opt for Secret. If they wanted to expose it all the way to the workflow action, theyād opt for Public. The decision is made by the developer.
Key Types
When Bubble introduced client-side actions and later server-side actions to match, it gave more reason for plugin developers to take advantage of the Additional Keys section in the plugin editor. A plugin developer could ask for specific keys and values from the user in the Plugins tab and use them at their discretion for operations like initializing elements, executing API calls and more.
There are two types available here:
Public keys are included in Context object and can be accessed for both client and server actions.
Private keys are also included in the Context object are not accessible on the client.
We know these to be true because not only does this inherently make sense as a logical decision from Bubble, but also because it takes almost no time to prove:
- Setup additional keys, Public and Private (Privacy - Additional keys - Droplr)
- Create client functions, Element and Action (Privacy - Element - Droplr, Privacy - Action - Droplr)
- Create server function, Action (Privacy - Server Action - Droplr)
- Wire up some workflows for testing (Privacy - Workflows - Droplr)
- Throw on a UI and run (Privacy - UI - Droplr)
Results? Both of your client functions will be able to successfully access the Public key but not the Private key, while the server function can access both. Privacy - Execution - Droplr
Key Uses
As seen above, simply setting a value to āPublicā or āPrivateā has nothing to do with exposing data. To reiterate from above, having access does not equate to accessing itself. A good developer would know the implications of their decisions early on, a great developer would know the implications of neglecting proper use. This is a good time to reflect on our own approach for keys, and itās how everyone should be building plugins: using the serviceās own documentation.
Imagine you were building the most powerful payments plugins for Bubble, something that would offer an alternative to Bubbleās built-in integration, really make a difference in whatās possible with Bubble and perhaps even change how people learn by using a third-party service they already know to educate them about development altogether. If you happened to choose Stripe as a plugin developer, landed on integrating PaymentIntents, learned about Strong Customer Authentication and realized you needed to implement Stripe Elements, you would be posed with this challenge from Stripeās documentation:
Next, create an instance of the Stripe object by providing your publishable API key as the first parameter:
var stripe = Stripe('pk_test_6tv7cR2saQ0So4FmdYhlpkOwgFcl8CuN');
Reference: Stripe Web Elements | Stripe Documentation
A competent plugin developer would understand the following concepts based on their research:
- Since Iām showing this to my user, itās on the client not server
- I need to load a JS library for my users
- I need to run functions using the JS library
- I need to show the rendered element from the JS library to my user
- I need to get the userās key for my JS library to work
- I need to ask my user for that key
ā“ Therefore, I need access to my userās key on the client side.
To accomplish this, that competent developer would setup up an Additional Key, set it to Public so they can access it on the client and then pull it to load the library, run their functions and ultimately hit their goal. To add even more confidence into their build, that developer would reference Stripeās documentation to see if itās safe or even permissible to pull the Publishable Key to the client which is where theyāll find the following:
Publishable API keys are meant solely to identify your account with Stripe, they arenāt secret. In other words, they can safely be published in places like your Stripe.js JavaScript code, or in an Android or iPhone app.
Secret API keys should be kept confidential and only stored on your own servers. Your accountās secret API key can perform any API request to Stripe without restriction.
Reference: API keys | Stripe Documentation
The above still doesnāt consider the longevity of tokens, functions with external dependencies, and other issues/arguments against running things client-side versus server-side. Weād delve into the basics of the other services mentioned in posts above but that may be better served as a good mental or development exercise for practice with plugin development.
We welcome healthy discussion any time of the day, but sharing incorrect and invalid information that can derail or discourage the community at large is not acceptable. 