Bubble.io API Security Best Practices

Step-by-step guide on How to secure API calls on bubble.io?

Bubble.io API Security Best Practices

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:

A user interface screen for configuring an API call to refresh a token. It includes fields for URL, method (POST), headers, body type, and parameters. There are options for capturing response headers and parameters for the body.

OR

A screenshot showing API request configuration with parameters for a "Refresh Token" action. It includes fields for client ID, client secret, grant type, and refresh token. Options for headers and response settings are also visible.

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.

Screenshot of a browser developer console displaying network request details for an OAuth 2.0 token refresh, with parameters including client ID, client secret, and grant type.


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

A screenshot of a software interface showing a form titled "Refresh Token." It features a POST method with fields for URL and endpoint values, and a Content-Type header set to "application/x-www-form-urlencoded."

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:

A screenshot of a web application interface for configuring a "Refresh Token" API call. The configuration includes URL and endpoint fields, headers, and parameters like client_id, client_secret, grant_type, and refresh_token. Red arrows highlight fields with static values marked as private. A note indicates that all parameters, except the refresh token, are static and should be private.

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:

A screenshot of an API configuration interface. It includes fields for setting up a POST request with URL parameters, headers, and JSON body parameters like , , , and . An annotation points to a dynamic parameter with the note: "Dynamic parameter removed from API connector."

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.

A user interface showing a data type named "Salesforce" with fields such as "access_token," "expired_by," and "refresh_token." The "Salesforce" type is publicly visible, and fields are categorized by type, like text and date. A form for creating a new field is also visible.

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:

A screenshot of privacy settings in a bubble.io interface. The "Salesforce" data type is selected, showing detailed rules for logged-in users to view their own data and permissions for other users. Options include fields for access token, created by, and others, with checkboxes for permissions.

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.

Screenshot of a user permissions settings page. It shows options for user roles and data access levels, with drop-down menus offering permissions such as "View and edit." Two users' email addresses are visible, alongside options to invite or transfer users. Navigation tabs are on the left side.

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.