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?