Retool - Security Considerations

We are currently exploring using retool to build out a management portal for external clients (1000+ external users, 100+ tenants), and are currently looking into things from a security perspective.

The ability to tie into resources (databases, APIs, etc.) is great, but from a security perspective, we're not seeing much beyond row-level security which seems severely limited in itself.

Are there any mechanisms to allow for:

  1. Server-side input validation prior to write (insert, update, POST, etc.) queries being executed? The idea would be to do more thorough checks against incoming parameters to ensure the changes being made are within the allowed scopes for the specific user.
  2. The ability to pass a session token (e.g., access_token, id_token, or similar from the retool login session) along with API requests that can be validated by internal services against the user and then our internal API can perform the corresponding action. This would not be ideal, but at least a workaround, in that it would limit us from using the built-in functionality for making read/write queries directly against a database, but at least we can write custom logic at an API-level to accomplish this.
  3. In an enterprise setting (currently testing within a business plan), using an OIDC mechanism for logins, the ability to set user-scoped tokens to the customer profile which are used in API requests. Again, less than ideal, due to reasons above.

Additionally, just doing a quick inspection of the network requests retool is making when loading an app, there is a concern due to the level of detail about resources that is exposed to the client. While any risks from exposing this information can be mitigated, we see no real reason the client even needs to know detailed information about what type of databases, the hostnames, port numbers, user name, etc., are being used. Is there any way to limit the exposure of this information?

1 Like

Hello @Samit_Ghelani!

Great questions, let me double check with our security team and get back to you with concrete answers.

From my experience, these are my thoughts:

  1. Write queries should fail if they do not match schema constraints on the Resource DB. We have various layers of permissions for which users can do what actions with specific resources.

  2. If 1 does not work, they can set up custom auth, or use the auth tokens from a successful auth in an API request to have another service work as middleware on top of the Resource/DB

  3. Can use OIDC for user login with ent. Not sure if we can do user-scoped but you can add users to groups and have group scoped permissions.

Let me know if you have more details about the server-side validation you are looking for, are you thinking data type enforcement? Or more so related to scopes as in which tables/DBs/rows or cols that are specifically being modified?

Also for additional reading, docs for reference:

-External apps tutorial | Retool Docs

-Manage organization users | Retool Docs

-Configure permission controls | Retool Docs

2 Likes
  1. Write queries should fail if they do not match schema constraints on the Resource DB. We have various layers of permissions for which users can do what actions with specific resources.

Schema constraints are fine, but for a multi-tenant architecture, at some level, you're going to have some form of "tenant id" that needs set as an attribute. At the moment, beyond having N flavors of a similar query with the tenant ID baked into the resource configuration, and then using group permissions to allow access to each, I don't see an easy way to simply specify the "tenant id" dynamically while ensuring spoof-proof security. At one level, you can set it as a user-attribute at the user-level, but when you start looking at users who should have access to multiple tenants, that breaks down quickly. To my first point about having "N flavors" that also quickly becomes a nightmare from a management standpoint, with needing to conditionally choose the correct resource to use based on the user.

  1. If 1 does not work, they can set up custom auth, or use the auth tokens from a successful auth in an API request to have another service work as middleware on top of the Resource/DB

This essentially requires 1) the user to log into the Retool application then 2) authenticate with a secondary identity/auth provider to get an auth token for use with a middleware, which isn't a great experience. In theory, if this were to work, we can store the 'token' to localStorage and just reference it in REST resources and the middleware can do what it needs to for authorization. I guess it could alternatively be a 'public' app but have the custom authentication take place for the resources, but that seems like it may not be allowed per the ToS.

  1. Can use OIDC for user login with ent. Not sure if we can do user-scoped but you can add users to groups and have group scoped permissions.

As far as I can tell, the user groups/permissions seems to be only constrained to API calls made to the Retool service layer, there's no way to extend this to a custom middleware.

[UPDATE] Looking at the SSO documentation here Configure SSO with OIDC authentication | Retool Docs, it sounds like what I initially asked in (3) is supported. That said, it would negate much of the benefit of using Retool's abstractions for data source connectors and connecting components "directly" to your data.

Let me know if you have more details about the server-side validation you are looking for, are you thinking data type enforcement? Or more so related to scopes as in which tables/DBs/rows or cols that are specifically being modified?

I think at a fundamental level (correct me if I'm wrong), Retool acts as a data source abstraction layer with a low-code, drag-drop frontend builder. That is, it's providing a nice interface for your underlying data stores. While there are use-cases where your end-user can be trusted within the bounds of user permissions and groups, there are also use-cases, especially with external apps/portals which are being marketed, that some level of server-side input validation is a necessity.

The validation is more to ensure that whatever data is being written is actually a valid or acceptable state for the user write. For example, at a very basic level, I would like to be able to just have a simple validation on if the "tenant id" being written for a new record is something that's allowed by the user (see example snippet below). A more complex case might be to ensure that a user hasn't bypassed client-side validation rules to write invalid data (e.g., from the example you linked for the patient portal, the user isn't able to spoof a value to get a larger quantity of medication than they're actually allowed).

function validateInput(data) {  //Where data is the incoming object to write to the resource
  if (!current_user.metadata.tenants.includes(data.tenant_id)) {
    throw new Error('User is not allowed to write to this tenant.');
  }
}
1 Like

Hi @Samit_Ghelani,

How would you differentiate between external users vs tenants?

Retool does offer our new feature Retool Spaces, where apps can be more or less 'parallelized' to partition between different user groups and adds at additional level of security can works as a top level layer that splits off what app/data the users have access to. I think is might be able to solve your concerns but let me know if this implementation style would make sense for your use case.

At the next level below the spaces are the group level of permissions where resources and queries can be scoped to only specific groups at the user level. But it sounds like you are looking to dynamically specify a 'tenant ID' type of property so that one user can have one or many IDs that grant them permissions to access different data sources.

Yes you are correct users would need to both log in the the Retool app and then pass through a second auth for resource which require such. Trying to store a token in the app state to use repeatedly instead of re-auth is something other users have brought up and is a bit more tricky to set up and currently not fully supported.

Yes your ask (3) should be supported. And yes you are correct Retool primary acts as a data source abstraction layer! It was initially designed for internal tools where it was assumed there was a level of trust and security among users with security layers and grouping systems/permissions to meet most security requirements. More recently we have moved into the external/public apps space where we are looking to improve and expand so your feedback and thoughts are very useful for helping us understand client needs.

How would you differentiate between external users vs tenants?

Either as a user attribute or a JWT claim that can be checked against.

Retool does offer our new feature Retool Spaces, where apps can be more or less 'parallelized' to partition between different user groups and adds at additional level of security can works as a top level layer that splits off what app/data the users have access to. I think is might be able to solve your concerns but let me know if this implementation style would make sense for your use case.

At the next level below the spaces are the group level of permissions where resources and queries can be scoped to only specific groups at the user level. But it sounds like you are looking to dynamically specify a 'tenant ID' type of property so that one user can have one or many IDs that grant them permissions to access different data sources.

In a model where you have multiple groups and resources/queries scoped to each group, you're looking at increased overhead. Even then, it doesn't really achieve much aside from ensuring certain parameters in a query are immutable (e.g., in this case, a tenant ID). Honestly, the validation on the tenant is just the absolute must-have to ensure data security, but broadly speaking it doesn't fully address the issue. The validation queries do against user attributes is fine, it's just there's a lot more that should ideally be supported.

Yes your ask (3) should be supported. And yes you are correct Retool primary acts as a data source abstraction layer! It was initially designed for internal tools where it was assumed there was a level of trust and security among users with security layers and grouping systems/permissions to meet most security requirements. More recently we have moved into the external/public apps space where we are looking to improve and expand so your feedback and thoughts are very useful for helping us understand client needs.

Yes, for internal tooling, this solution seems fine. For anyone that's actually using it for an external/public app, especially one that supports write, I would be curious to see how they're addressing these issues.