Bubble.io API Security Best Practices
Step-by-step guide on How to secure API calls on bubble.io?
What are the risks of not making secure api calls with bubble.io?
Exposing sensitive information, such as passwords and tokens, because of unencrypted data transfers and visible API keys in logs.
Unauthorized access and token theft.
Risk service disruptions, account takeovers, and potential compliance issues.
It opens the door to injection attacks and data leaks.
In the previous article, I have shown how to set API calls and OAuth in bubble.io using the bubble api connector.
A successful API call might look like in the images shown below:
OR
These API calls are not secure. Let me explain how.
- This API call, endpoint URL, and all its tokens (Client ID, Client Secret, Authentication token, refresh token, etc.) are visible on the developer console on each page load of the bubble.io application. It doesn't matter if I am using this API call or not. It will be visible to logged-out users (Unauthorised users) as well on any page load.
Best Practices for implementing secure API calls
Here are some of the best practices for implementing secure API calls and token management:
Step 1: Conceal API URL Endpoint
Now you must be wondering why should I hide my API URL Endpoint. Here is why:
- Exposing the endpoint could let malicious users access the API directly, understand my application's structure, and possibly exploit vulnerabilities. It also helps protect the privacy of my business logic and interactions with third-party services, maintaining both security and a competitive edge. Keeping the endpoint hidden adds an important layer of security to my application.
After understanding why, let’s dive into how.
As you can see in the screenshot attached below, I have divided the endpoint URL: login.salesforce.com/services/oauth2/token into 2 parts and put them in square bracket [url]/[endpoint]
Then I have defined url=login.salesforce.com/services/oauth2 and endpoint=token
Step 2: Safeguard Static Parameters
When making an API call, certain parameters remain constant, regardless of whether the call is a Data call or an Action call. These are known as static parameters. It is crucial to ensure that all these static parameters are kept private. By doing so, you protect sensitive information from being exposed or accessed by unauthorized users. This will prevent them from being visible on the client side through the developer console. Checkout the screenshot below:
On the Bubble.io app page load, the browser downloads all api calls on the user’s device, and if you don’t keep the static parameters like client_id, and client_secret private; anyone can access these parameter values on their device using the console.
Step 3: Manage Dynamic Parameters Securely
What are the dynamic parameters in API calls?
- When making an API call, some parameters may change based on specific inputs or conditions at the time of the call. These are called dynamic parameters. Unlike static parameters, which stay the same whether it's a Data call or an Action call, dynamic parameters are flexible. They can be updated with values that are generated or provided during each API request. This flexibility allows the API call to adapt to different situations or user inputs as needed.
Let’s understand how to make them secure.
Once I initialize the API call, I will remove all the parameters from the API connector that are not private. On the Above image of step 2, you can see that refresh_token is not private and because of that, it will still be visible on the developer console on every page load. Check out the below image:
This is still risky so remove it from here and because it is a dynamic parameter that varies from user to user, I will store all the dynamic parameters in the database. Check the screenshot below:
Step 4: Implement Privacy Rules for Dynamic Data
As shown in the screenshot above of step 3, the refresh token is a dynamic parameter that I did not make private. It is stored in the database as a field in a certain data type.
Without privacy rules, data is basically open to anyone using the app. Any user can possibly access the database data for that specific type. This includes data from things like repeating groups, text elements, and API requests. Any workflows that create, change, or show data that can lead to unauthorized changes or exposure of data.
So here I have defined privacy rules that will accomplish the following:
Do not show the refresh token, access token, and access token expiry date to any users who are logged out.
When a user is logged in, the application will allow access only to their own refresh token, access token, and access token expiry date. Users will not be able to see anyone else's refresh token, access token, or access token expiry date.
Checkout the image below to check the privacy rules setup:
Step 5: Replace Initialised API Call Response with placeholders
Let’s understand how bubble.io works:
When I set up an API call in Bubble.io, the API Connector plugin automatically makes a test call to understand how the API response is structured. This process creates a response schema - a template that represents the format and structure of the data the API returns. This schema helps Bubble understand what kind of data to expect when the API call is made in real-time.
After the initial test call, the response schema is stored in my app's configuration, specifically in a file called app.json. This file is part of my app's settings and can be accessed by others if it's not secured properly. Therefore, if the test API call includes sensitive information - like access tokens, API keys, user data, or app IDs - this information will be saved as part of the schema.
Issue: If I don’t clean up these sensitive details before deploying my app, they might become visible to anyone who can access the app.json file or inspect the API response structure.
Solution:
As you can see in the image shown below, my initialized api call contains actual sensitive information that will be visible on the developer console and if it is leaked, my account, my credits, my data, etc can be misused.
Now, when you save it, you will know the exact type (like text, number, yes/no, file, image) of the data each field contains. check the image below for more clarity.
The reason for the bubble.io to save it is just to understand data structure whenever an API call is made that means, in manual response if there is ‘access_token’ and the type of field is text then I don’t need actual access_token but some arbitrary text which will let api response to identify as text.
So I will replace the existing original data with a placeholder for the same type of data
Following these steps, your app's response schema will contain placeholders instead of sensitive data. When you deploy your application, any potential exposure of sensitive information will be avoided. This practice enhances the security of your app, especially when dealing with data like access tokens, API keys, and user information.
Step 6: Limit Developers' Access to Dynamic Tokens
Now, developers working with applications and having access to the Bubble.io app editor can also access the data. However, not every developer needs to see this information. Bubble.io offers a way to restrict developer access to data as well.
Go to Setting → Collaboration and restrict the data access for developers who don’t need it.
For Data, there will be 4 options explained below:
No permission - (cannot see or edit any database data in Development or Live)
View only - (can view data but cannot change it in the database editor)
View and run as - (can view data and use the run as feature)
View and edit - (can view and freely edit data)
How did I secure API Calls & tokens till now?
With Step 1, I ensure that no user can identify the API calls the app is making, regardless of their login status.
With Step 2, static parameters like the client ID and client secret are completely inaccessible in the developer console for all users, whether logged in or out.
With Step 3, dynamic parameters are hidden for all users (authorized/unauthorized) in the developer console of the browser on page load.
With Step 4, dynamic parameters are hidden from logged-out users, and logged-in users are restricted from accessing tokens of other users.
With Step 5, Anyone (authorized/unauthorized) won’t be able to find actual data in bubble.io’s saved API response because I have replaced it with placeholders.
With Step 6, developers who don't need to view or edit data are denied access.
This is how I recommend securing API calls and tokens from any user, logged-out users, logged-in users, and unauthorized developers.
Special Cases & Your API Practices
Tell me, how you are setting up your APIs in bubble.io currently? & buy me a coffee 😉. Also If you would like to learn about some special cases tips for API Security, click here.