Securely managing ownership relations in Softr.io

Edouard Demotes
TRACTR
Published in
8 min readFeb 25, 2023

Introduction

What is Softr.io ?

Softr.io is a no-code web app builder that allows users to create custom web applications and websites without any coding knowledge or experience. The platform offers a range of templates, drag-and-drop components, and integrations with popular tools like Zapier, Airtable, and Stripe to make the app building process simple and intuitive.

Forms and entities creation

To create a form, users can use Softr.io’s editor to add form fields such as text areas, checkboxes, radio buttons, and dropdown menus onto their page. They can customize each form field by editing the label, formatting options, and data validations.

Once the form is created, users can choose to connect it to a database to store form submissions, such as Airtable.

Our use case: Agencies listing

Our application is essentially an agency directory that allows users to browse existing agencies. Logged-in users can create new agencies which are linked to their creator.

Additionally, users have the ability to edit the agencies they’ve created at a later time.

Ownership relation

The database used for this application is Airtable. The link between agencies and users is managed using a relation in Airtable.

Specifically, the “agencies” table in Airtable has a column Owner that links each agency to its creator. This column is set up as a "linked record" field, which allows it to reference the corresponding record in the "users" table.

When a user creates a new agency, the unique identifier of the user is automatically included in the linked record field of the new agency record. This links the agency to the user who created it.

User’s primary key

The unique identifier of users in this application is the RecordID value in the Users table. This value is a unique identifier generated by Airtable, which is a random string.

Allowing users create agencies from a form

Here’s how you can set this up in Softr:

  1. Create a form in Softr for users to create new agencies. Add all the necessary fields such as agency name, description, etc.
  2. Add a hidden input field to the form that will contain the unique identifier of the logged-in user (i.e. RecordID).
  3. In the hidden input field settings, map to Owner and select "Logged-In user" and choose "Record ID".

When the user submits the form, the hidden input field will automatically capture their RecordID and send it along with the other agency information to Airtable.

In Airtable, the Owner field in the new agency record will be populated with the unique identifier of the user who created the agency, establishing the relationship between the agency and its creator.

Security issue

This is currently the only way to create an ownership relationship between a user and their agency through Softr.io. However, this approach presents a risk, as it’s possible for a user to manipulate the frontend form and use the identifier of another user to create an agency in their name.

For instance, let’s say User A knows the identifier of User B. User A could use the Chrome inspector or an API call to modify the RecordID value sent to Airtable and create an agency for User B.

In other words, this method doesn’t provide a foolproof way of ensuring that an agency is only created by its rightful owner, as users can potentially manipulate the hidden input field and submit false information.

Even if I use unique identifiers for my users, it’s still possible for someone to discover these identifiers. Since my agencies reference their corresponding users, Softr’s API will always return this reference. Although the frontend only displays certain fields, Softr’s API always returns all the fields defined in Airtable. As soon as one piece of data from a table is visible on the frontend, all other columns become accessible as well. This is important to keep in mind when developing an application with Softr. This issue is well described in this article: https://community.ncscale.com/c/resources/how-to-build-a-secure-marketplace-with-softr-io-and-airtable.

Get the identifier of another user

When calling the API to retrieve agencies, the front-end calls this endpoint:

https://xxx.softr.app/v1/datasource/airtable/{...long id...}/data/

The response looks like this :

{
"records": [
{
"id": "recmQaUoI1wQxVqJe",
"fields": {
"Services": "Wordpress, Android",
"Logo": "PXL_069a.jpeg (<https://v5.airtableusercontent.com/v1/15/15/1_31LOUkXvyCyPU>)",
"Name": "Agency Name"
},
"createdTime": "2023-02-21T18:05:23Z",
"table": null,
"linkedTables": null
}
],
"offset": null
}

I append the agency’s record id to the previous URL :

https://xxx.softr.app/v1/datasource/airtable/{...long id...}/data/recmQaUoI1wQxVqJe

Then, I call again the API (with the same POST method) :

{
"totalCount": 1,
"records": [
{
"id": "recmQaUoI1wQxVqJe",
"fields": {
"Services": "Wordpress, Android",
"Logo": "PXL_29a.jpeg (<https://v5.airtableusercontent.com/v1/NUYci_Ohb1_3UkXvyCyPU>)",
"Name": "Agency Name"
"ID": "recmQaUoI1wQxVqJe",
"Created": "2023-02-21 18:05",
"LastModified": "2023-02-24 00:22",
"Owner.ID": "recsPsuIgUOoq27XV",
},
"createdTime": "2023-02-21T18:05:23Z",
"table": null,
"linkedTables": null
}
]
}

I can see all fields from the agency, including the Owner.ID!

Note that the relation field Owner is not included here, but only the “rollup field” Owner.ID that exposes the owner’s record ID. This is mandatory for our application to have this “rollup field” in order to check ownership during agency update:

Hidden field configuration for Owner.ID

Now I have the user record ID of another user : recsPsuIgUOoq27XV.

Create an agency for another user

Now that I have the user ID of a user B I am able to create an agency on his behalf:

  1. After logging in as user A, I return to the agency creation form.
  2. I enter all the necessary data to create the agency.
  3. I open the Chrome inspector and submit the form.
  4. In the Network tab, I capture the call made to the API as a cURL command.
  5. I change the user identifier in the payload to B.
  6. I re-run the new modified request.
Copy API call to cURL

When I check in Airtable, the agency has been created with the user B as Owner.

Workaround: Users masks & Airtable automations

To work around this issue, I added another table called UsersMasks that serves as a screen between users and agencies. Agencies now have a relation to a mask instead of a user, and masks have a relation to a user. This table simply has a relation field to the users table.

UsersMasks table

As a result, the list of agencies now provides access to the RecordID of the masks, not the users.

Care is taken never to list masks in Softr, or any entity that has a direct relation to users. This means that the API endpoint that lists masks and therefore the RecordID of users is never exposed.

To ensure that each user has a mask, an automation is added to Airtable that creates a mask whenever a user is created.

Airtable automation for creating user’s mask

It is now impossible to link an agency to its owner from the front-end and it is impossible to find others users identifiers.

Agency form

I also need to modify the agency table and the agency creation form:

  1. I remove the Owner column that links to the Users table.
  2. I add a TempOwner field that is a direct relationship to the Users table. However, this field will always be empty.
  3. I add an OwnerMask field that is a relationship to the UsersMasks table.

In the agency creation form, I remove the old hidden Owner field. I create a new hidden field and select "map to" TempOwner, then "Logged-In user -> Record ID". So when creating an agency, the TempOwner field will be populated with the current user’s ID.

Hidden input configuration

Finally, I create an Airtable automation that performs the following operations when creating an agency:

  1. Retrieve the TempOwner value from the newly created row.
  2. Retrieve the ID of the mask corresponding to the TempOwner user.
  3. Fill in the OwnerMask field of the new agency with the ID of the mask retrieved in the previous step.
  4. Clear the TempOwner field of the new agency.
Airtable workflow for replacing owner’s id
Airtable automation for replacing owner’s id

If I want to create an agency for someone else, I will need its RecordID, which I can’t have because agencies lists no longer returns anything other than mask RecordIDs.

Conclusion

In conclusion, it is possible, but complex, to manage ownership relations in Softr in a secure manner. It is important to be cautious not to display entities directly linked to users in the front-end, as the Softr API could be used to retrieve user IDs. This would allow someone to impersonate another user when creating entities.

The mask method works well, but is cumbersome to set up. It requires adding a pivot table, an additional field in the Agencies table, and two Airtable automations.

Others solutions

There are other ways to address this issue. Enabling reCaptcha on the creation form can make it more difficult for someone to impersonate another user, but it does not completely prevent it. Additionally, Softr has plans to add more control during entity creation accordingly to their roadmap.

Softr’s roadmap

If you are building an application, with Softr & Airtable or not, that requires ownership relations and if you have any questions or comments, please feel free to reach out.

Thank you for taking the time to read and if you found this article helpful, please share it with others who may find it useful as well.

Update (04/03/2022)

Softr has fixed this issue. It is not possible anymore to change the current user’s recordId in a form.

Although the front-end still sends the user’s recordId, the back-end overrides it with the correct value. I tested the API using cURL and attempted to modify or remove the user’s recordId, but the correct value was successfully inserted into Airtable.

I think this is still a good practice to minimize the visibility of user recordIds in order to prevent potential future complications.

More details in this threaad : https://community.softr.io/t/securing-ownership-relationships-in-softr/2221

--

--

Edouard Demotes
TRACTR
Writer for

I work at Tractr as CTO, a startup studio specialized in web applications. I’m a full-stack developer and passionate about TypeScript.