Embedded permission management & RLS

Our embed set-up relies on permissions settings to ensure that each user sees the right data. Because permissions are specific to a dataset, it requires one of the following:

  1. Before showing users the embed iframe, we need to know what datasets are used on a dashboard and pass in the permissions for the given datasets, which can be accomplished with one of the following:
    a. By calling the API on the fly every time which takes time and slows down the user experience
    b. By storing the list of datasets per dashboard in our database which has the risk of becoming stale if we add a new datset to the dashboard without updating our database
  2. Passing in filters for ALL possible datasets (this has a risk of causing the URL to become fairly long, 2k limit for URLs?)

After considering the trade-offs, we’ve currently decided to go with option 1.b. with some CI/CD steps to mitigate the risk of stale data in our database (ex. anytime we merge to main, we parse the canvas dashboards and trigger an update to our database record of what datasets + fields should be filtered for that dashboard). Any suggestions on how to improve this? Has anyone come up with something better?

1 Like

Hi @anya.conti

Context

If I understand your situation correctly:

  • You have an embedded dashboard built on multiple datasets.
  • Row-level permissions need to be set for each dataset manually in the embed payload, which can be cumbersome and prone to errors.

And the problem you’re facing:

  • It’s hard to manage and easy to misconfigure permissions, especially with multiple datasets.

Potential Solution:

We’re exploring a potentially more streamlined approach that could simplify your workflow in the future, using user_attribute defined in Holistics.

The main idea is to move Row-level Permissions to the Modeling (As-code) layer. This will make them easier to maintain and ensure consistency, instead of requiring manual configuration through Embed Payload.

Here’s an overview of how it could work:

(1) Create a User Attribute in Holistics

First, define the user attribute in Holistics through the User Management section.
For more details, please refer to our documentation.

(2) Define Row-Level Permissions in Holistics As-Code

Instead of setting permissions in the embed payload for each dataset, define them directly in Holistics. For example:

Dataset first_dset {

  always_filters: {
    filter1 Filter {
      field: ref('continent_codes', 'code')
      enabled: true
      default {
        operator: 'is'
        value: ['asia']
      }
    }

    filter2 Filter {
      field: ref('users', 'email')
      enabled: H.current_user.is_biz_user   // use UserAttribute here
      default {
        operator: 'is'
        value: H.current_user.email         // use UserAttribute here
      }
    }
  }

}

Dataset second_dset {
  
  always_filters: {
    filter1 Filter {
      field: ref('continent_codes', 'code')
      enabled: true
      default {
        operator: 'is'
        value: ['eu']
      }
    }

    filter2 Filter {
      field: ref('users', 'email')
      enabled: H.current_user.is_biz_user   // use UserAttribute here
      default {
        operator: 'is'
        value: H.current_user.email         // use UserAttribute here
      }
    }
  }
}

By defining row-level permissions in the modeling layer, you would ensure they are consistently applied across all datasets.

Note​: The syntax provided above is a preliminary draft from our design document. The final version may vary.

(3) Use User Attributes in Embed Payload

You can then pass the values to user_attribute in your embed payload. Here’s an example:

// Embedded payload
embedded_payload = {
  permissions: {},
  user_attribute: {
    is_biz_user: true,
    email: '[email protected]'
  }
}

This way, you won’t have to manually configure row-level permissions for each dataset via embed payload, reducing the risk of errors.

For more information, you can refer to this doc

We would love to hear your thoughts or any suggestions you might have. What do you think about this potential approach? Your feedback would be invaluable as we consider implementing this feature.

Thanks so much for the details response! I love the always_filter options in a dataset as a general concept, not just for RLS, which it looks like this also seems to covers (ex. always_filters on continent_codes.code is eu). I also love the idea of this approach of managing the RLS restrictions in code, as well as the idea of being able to enable / disable the use of the filter by a user-attribute.

But want to confirm a few things to make sure that the proposed solution will work for us:

  • Am I understanding correctly that for the embedded_payload, we could pass in any user_attribute value? It doesn’t necessarily need to be for a user who exists? Ex. no user has the value of ‘[email protected]’ when passing that into the embedded payload. It seems like this works since it’s not passing in a user ID or something.
  • The “default” seems to imply that this filter value can be overridden. How?
  • I’m guessing if we used something like H.current_user.is_biz_user to determine whether the filter is enabled or not, this would need to be set for all users? What would happen if a user doesn’t have that attribute set, or it’s an admin who can’t have a user attribute? It uses a default value of some sort for the user_attribute?
  • Similarly to the above, what about a filter that is always enabled, but the filter itself relies a user attribute? What would happen if a user doesn’t have that attribute set, or it’s an admin who can’t have a user attribute? It uses a default value of some sort for the user_attribute?
  • Do the filters independent of user attributes (like the continent_codes.code = eu filter) apply to admins as well as everyone else?
1 Like

yes, you’re correct


yes, this is correct as well.
It’s not required to have the actual user in Holistics to pass value to the user attribute. You can pass any values to the user attribute from your Platform (e.g., user email)


If I understand your concerns correctly, you’re asking about two main points:

  1. ​Admin Application​: Will the value in always_filter apply to admin users?
  2. ​User Attribute Handling​: What happens if there are no values for user attributes?

Tentative Solution:
We are considering supporting an if else syntax to control behavior based on user roles. Here’s an example of what it might look like:

filter2 Filter {
  field: ref('users', 'email')
  enabled: if (H.current_user.is_biz_user) 
           then true 
           else false
  default {
    operator: 'is'
    value: if (H.current_user.email) 
           then H.current_user.email 
           else null
  }
}

This approach would allow you to dynamically enable filters and set default values based on the user’s attributes or roles.

Status:
Please note that this solution is not yet finalized. Our team is still discussing the final design. We appreciate your patience and will share updates with you as soon as they become available.


I hope this clarifies your concerns. We’re keen on hearing your feedback or any suggestions you might have regarding this approach.

Hi Khai,

That looks great, thank you so much! I think that answers all the questions I had really well. I can’t wait for this to be released, it would improve our workflow so much!

All the best,
Anya

1 Like