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

Hi @Khai_To
I understand this type of update may be in development. Do you have any updates on when the ability to manage permissions via code may be available in the platform?

Thank you!
Bob

Hi @Bob_Adams,

Thanks for your interest! We’re in the final stage of private-beta-releasing our “Row-level Permission as Code” feature.

You can find more details in our documentation here.

Just a quick note:

If you are using ​Embedded Analytics ​ with row-level permission, this needs to be set up in our new ​Embed Portal ​ (the next-generation platform for Embedded Analytics). The current Embedded Dashboard does ​not ​ support row-level permission as code.

We’ll be making a separate announcement about the new Embed Portal soon. I’ll keep you updated as soon as there’s more news.

Below is the high-level mechanism of our upcoming Embed Portal, we will let you know when there is an update.

Hi Kai,

Thanks for the response! We’ve got some questions / concerns with the planned implementation and how it will work with our set-up.


Some information on our current set-up

  • Currently, we have quite a few customers and quite a lot of dashboards. Critically, not all customers see the same dashboards. We have some core dashboards that all customers get to see. We also have some custom dashboards that can be shared between a few customers or specific to one customer. We need a scalable to manage who has access to what.
  • We have the ability to set a specific dashboard to load when switching to a specific page.
  • We have built an admin tool where our support team can modify which custom dashboards a customer has access to, as well as modifying which dashboards are “core” dashboards that all customers can see, and which dashboards are used as “landing pages” on specific pages of the application.
  • Minimal onboarding set-up for new customers. Currently since all customers have access to core reports, this means that we have NO reporting set-up for those customers. We have minimal reporting set-up for giving them access to a core-report, either when they are new or have been a customer for years since it’s a simple change in our admin tool.
  • We have built a drop-down menu where customers can switch between any dashboard that they have access to, where it’s clearly marked as “Core” and “Custom” ex:

CORE
    Dashboard 1
    Dashboard 2
CUSTOM
    Dashboard 3
    Dashboard 4

  • We have the ability to set specific URLs for specific dashboards. This allows users to bookmark specific pages and load those specific dashboards quickly.
  • Having different URLs also gives us the ability to see which customers are loading which dashboards and for how long, usage metrics that would likely go away if all we’re loading is one single iframe for ALL dashboards.
  • And we have one dashboard that’s used more as a pop-up with specific parameters (ex. when looking at item A, I click to see more details, which loads pop-up that’s just a dashboard embedded with a single graph filtered to that one item using the filter value passed into the payload). This is essentially drilling down, but from our application to holistics.
  • We need a way to ensure customers are only seeing their data, whether it’s a core/custom dashboard, or the pop-up drill-through. We’ve built this into our internal tooling, but there’s edge-cases where this logic could fail if we’re not careful.

Questions on the new feature

  1. It looks like each “portal” is set up in holistics code and has a static set of datasets / dashboards. If every customer needs to see a different set of dashboards, does this mean we’d need a portal for each customer? This seems like a lot to set up and manage. We’d likely still need our in-house admin tool then to manage which customers can see which portal, so this would require quite a bit of work on our end to switch to using. This also likely means a lot of on-going work to set-up new customers, and possibly to maintain already existing customers as well.
  2. It looks like this would remove the need of our drop-down for dashboard selection, so we’d need to get creative with a way to mark which dashboards are core vs custom. Maybe titles? This is probably not as important but still a consideration.
  3. This looks like it would take away our ability to do all of the following. Can you confirm if that’s true, or if there’s workarounds?
    A. Specify which dashboard is used as the “landing pages” on specific pages of our application.
    B. Allow users to bookmark specific dashboards
    C. Seeing usage metrics per user and dashboard and link that back to our internal data. This might be possible given how we’re passing in the “embed_user_id” and “embed_org_id” but I want to make sure.
  4. I’m unsure if this feature would work on the single graph that’s being used to drill into information on one specific item (we don’t want lots of extras here, minimal functionality), so it might still require us to maintain our current set-up for that. Maintaining both methods of RLS + embedding sounds like a lot.
  5. Is the Embedded Self-Service something that we can turn off?
    A. Based on your image, it looks like maybe we can just not pass in the datasets. We would want to make sure users don’t see prompts for being able to do it, but then not be able to do anything. This seems like a cool feature, but we’d want to curate our datasets a lot more to make them user-friendly before opening it up, and I’m not sure that’s work we’re immediately going to prioritize.
    B. I’m also curious how the “custom dashboards” would work. Would those be one time use? Saved as canvas dashboards? If they save as canvas dashboards, does that require a github PR? And similarly how would collaboration work?
  6. Given the mention of “embed users” with distinct user and org IDs, would we be charged per seat for these users?
  7. This seems like a big change versus how we’re currently showing embedded reports to customers. We were prepared to make that change as part of the migration to holistics, but we’d need to check with our support, customer, and product teams that we’re definitely ok making these additional changes for our users. This will likely requires some work on our side to prep/train our users on as well.

Summary

Overall the feature seems really cool, but it might not meet our needs in quite a few ways and would likely be a lot of work to switch to and maintain. Is there any way we could get the ability to pass in the user_attribute value to the embedded payload like you originally proposed, and continue to use the current method of embedding of single dashboards?


Thanks so much,
Anya

P.S. If we can’t make this work for us, we have an idea for a workaround, but it might not be possible with the upcoming auto-publish feature as explained here, so I want to consider that as well.

Hi @Bob_Adams and @anya.conti,

Thank you for your thoughtful questions. We’re reviewing them and will follow up with a detailed response soon. We also plan to share a separate announcement regarding the Embed Portal, where we’ll address your queries in more detail.

I want to reassure you that, based on your feedback, we understand the Embed Portal isn’t the right fit for you at this time.

After discussing internally, we’ve decided to support Row-level Permission as-code and User Attributes in our current Embedded Analytics setup (single dashboard embedding).

This means you do ​not​ need to migrate to the Embed Portal to take advantage of these features.


Here’s how it will work once the feature is available:

Step 1:​ Set up Row-level Permission in your dataset as usual

Dataset ecommerce {
  label: 'Ecommerce'
  models: []
  relationships: []

  permission country_access {
    field: ref('countries', 'name')
    operator: 'matches_user_attribute'
    value: 'country_attribute' // user attribute
  }
}

Step 2:​ Your developers can pass the value for country_attribute in the Embed Payload for each user, giving you full control:

payload = {
  // ... other params
  user_attributes: {
    country_attribute: 'vietnam'
  }
}

(Currently, this isn’t supported yet, but this capability will be added in the future.)


To clarify:​

  • You can continue using your existing single-dashboard embedding; it is ​not​ necessary to switch to Embed Portal to leverage Row-level Permission as-code or User Attributes.
  • We cannot share the exact timeline when this will be supported for Single Embedded Dashboard (tentatively in 2025-Q3) as our team is focusing on releasing our Embed Portal. We will let you know when there is an update on our side.

If you have any further questions or need clarification, please let us know!

2 Likes

Hi Khai,

Amazing, so glad to hear, we can’t wait for this feature! Really appreciate the holistics team helping to work with us on this.

All the best,
Anya

1 Like