What row-level security is
Row-level security (RLS) filters the rows a dashboard returns based on who is viewing it. The dashboard definition — the charts, the calculations, the layout — stays identical. What changes is the underlying query’s WHERE clause.
Alice in the Acme tenant logs in and sees Acme rows only. Bob in Globex logs in and sees Globex rows only. Same URL, same workbook, different data.
Why multi-tenant embedding needs RLS
If you ship a single Tableau workbook to a single tenant, authentication is enough — only their users can open it. The moment you host one dashboard for many tenants, that stops working. You need a mechanism that:
- Filters at query time, not at render time — bytes never leave the database that shouldn’t.
- Can’t be bypassed client-side — tampering with a URL or cookie shouldn’t grant access.
- Scales to thousands of tenants without creating a workbook per tenant.
RLS is that mechanism. And critically for embedded analytics: every major BI vendor supports it, but each in its own way. Embedportal normalises the configuration.
The Embedportal model
Embedportal models RLS in two layers:
- The claims — a set of attributes about the viewer (tenant, region, role, etc.) that travel as JWT claims on every embed request. Defined in your user profile, enriched by your backend, signed by Embedportal.
- The rule — the filter, defined once on the BI vendor’s data source. Reads the claim via
USERATTRIBUTE()(Tableau), an Effective Identity (Power BI), or a session tag (QuickSight), and applies aWHEREclause at query time.
You configure the claims once in Embedportal. You configure the rule once per data source in the BI vendor. Every dashboard built on that data source inherits the filter.
Available attributes
Standard attributes ship with Embedportal and map to columns on the user profile. Custom attributes are opened up via user tags.
| Attribute | Source | Example value |
|---|---|---|
| organization_id | viewer’s current tenant | ORG_ACME |
| user_email | viewer’s primary email | alice@acme.com |
| region | user profile → region | emea |
| department | user profile → department | sales |
| role | viewer’s access level | manager |
| custom / tag | anything on the user tags list | cost_center=CC_042 |
note — attribute names become JWT claim names verbatim. Pick identifiers that match what your BI vendor expects to read.
Enable RLS on a dashboard
- Open the dashboard configuration. In Embedportal, go to Navigation, open the dashboard, and scroll to the Security panel.
- Toggle “Enable RLS”. RLS is only available when the embed mode is Authenticated. If you’re on Anonymous, switch modes first.
- Select attributes to forward. Tick the attributes that your data source depends on. Each ticked attribute becomes a claim on the signed JWT. A typical multi-tenant setup needs only
organization_id; geography filters addregion; role-based visibility addsrole. - Save. From the next embed request onward, Embedportal signs tokens with the selected claims.
Wire RLS in Tableau
Tableau exposes JWT claims to the workbook via USERATTRIBUTE(). Add a calculated field on the data source and use it as a data source filter (not a view filter — data source filters run server-side in the query).
// calculated field: [Organization Filter]
[Organization ID] = USERATTRIBUTE('organization_id')
// calculated field: [Region Filter]
[Region] = USERATTRIBUTE('region')
// calculated field: [Role Filter]
[Access Level] = USERATTRIBUTE('role')
Right-click the data source → Edit Data Source Filters → add each calculated field as TRUE. Publish the workbook.
Tableau will now inject the viewer’s organization_id into every query. If a query tries to return a row from another tenant, the data source filter rejects it.
Wire RLS in Power BI
Power BI uses roles defined on the dataset. Each role carries a DAX filter that reads a dynamic user attribute. In the dataset (via Power BI Desktop or service), create a role:
-- Role: "Tenant Scope"
-- Filter applied to the [Organization] table:
[OrganizationId] = USERPRINCIPALNAME()
-- or for custom claims, read from the Effective Identity:
[OrganizationId] = USERPRINCIPALNAME()
&& [Region] = CUSTOMDATA()
Embedportal passes the JWT claims as Effective Identities on the embed token request, so the Power BI service applies the role automatically for the duration of the session.
Wire RLS in Amazon QuickSight
QuickSight offers two RLS modes:
- Dataset-based RLS — you publish a permissions dataset that maps users to values. Works when you have a stable users table.
- Tag-based RLS — the one Embedportal uses. You define session tags on the embedding session, and the dataset filters on them at query time. Perfect for multi-tenant SaaS because it scales without creating rows per user.
In QuickSight, open the dataset, toggle Row-level security → Tag-based, and declare tag keys like organization_id and region. Embedportal forwards the matching JWT claims as session tags when it calls GenerateEmbedUrlForRegisteredUser.
Wire RLS in Metabase
Metabase exposes locked parameters on signed embeds. Open the dashboard, click Sharing → Public link → Embed, mark the tenant and region parameters as Locked.
Embedportal signs the Metabase embed JWT with params filled from the viewer’s claims:
{
"resource": { "dashboard": 42 },
"params": {
"organization_id": "ORG_ACME",
"region": "emea"
},
"exp": 1747486500
}
Because the parameters are locked, viewers cannot edit them in the UI and the Metabase query plan always applies the filter.
Per-dashboard overrides
Sometimes two dashboards should filter differently even for the same viewer. A Revenue — EMEA dashboard should always show EMEA rows; a Revenue — APAC dashboard should always show APAC rows — regardless of where the viewer sits.
Embedportal supports per-dashboard overrides. On the dashboard’s Security panel, add an override entry:
{
"rlsEnabled": true,
"rlsOverrides": [
{
"key": "region",
"source": "custom",
"value": "emea"
}
]
}
With source: "custom" the override wins over the viewer’s profile value. With source: "region" (the default) the viewer’s profile supplies the value. Useful shapes:
- Fixed slice — regional and segment-specific dashboards.
- Force a role — e.g. always pass
role=vieweron a read-only public dashboard, regardless of the caller’s actual role. - Fallbacks — set a
defaultValueused when the viewer’s profile field is empty.
Verify and audit
After enabling RLS, always run the two-tenant test before shipping:
- Create two test users in two different tenants with at least one distinguishing row in each.
- Sign in as the first; confirm only that tenant’s rows appear.
- Sign in as the second; confirm the other tenant’s rows appear — and crucially, nothing from the first.
- Inspect the audit log in Embedportal — every embed request shows the claims that were signed into the JWT.
The audit log is searchable by user, dashboard, timestamp, and tenant. Stream it to your SIEM or warehouse for retention beyond Embedportal’s default 13 months.
Common pitfalls
- Dimension filter, not data-source filter — in Tableau the calculated field must be a data-source filter. Dimension filters run after the query, can be overridden, and don’t protect the wire.
- Case mismatch —
USERATTRIBUTE('organization_id')is case-sensitive on the claim name. Match exactly. - NULL claim — if a user’s profile field is empty, the JWT claim is missing, and a filter comparing against
USERATTRIBUTE()returns NULL, which in many dialects means no rows match. Always set a default in the override. - Caching across tenants — Tableau and Power BI cache results keyed by the query plan plus the user attribute. Ensure the attribute is part of the cache key (it is, by default, when used in a data-source filter).
- Global admins — if you have internal staff who need to see every tenant’s data, sign their tokens without RLS claims from an admin endpoint. Do not hardcode the bypass in the workbook.
13. FAQ
What is row-level security in an embedded dashboard?
Row-level security (RLS) is a mechanism that filters the data in a dashboard based on who is viewing it. The dashboard definition stays the same; the rows returned are scoped to the viewer's tenant, region, role, or custom attributes. In embedded analytics, RLS is essential for multi-tenant SaaS products that must never leak one customer's data to another.
How does Embedportal enforce RLS across different BI vendors?
Embedportal translates a single set of RLS attributes into each vendor's native mechanism: Tableau receives them as User Attributes readable via USERATTRIBUTE(); Power BI receives them as Effective Identities on the dataset role; QuickSight receives them as session tags applied to the embedded session. The user-facing configuration is the same regardless of vendor.
Can a signed JWT be tampered with to bypass RLS?
No. JWTs are signed with a secret that only Embedportal and the backend possess. Any modification invalidates the signature, and the BI vendor refuses the request. As long as the secret is not leaked and tokens are short-lived (5 minutes is typical), RLS cannot be bypassed client-side.
Do I need to model RLS separately for each dashboard?
No. RLS rules are modelled once on the data source (Tableau calculated field as a data source filter, Power BI RLS role, QuickSight RLS dataset). Every dashboard built on that data source inherits the filter automatically.
Can I override RLS per dashboard?
Yes. In Embedportal each navigation item can override the default attribute source. For example, dashboard A can always force region=emea regardless of the viewer's profile region. This is useful for regional reports where the tenant is the same but the geography slice is fixed.
Does RLS work with the free public dashboard mode?
No. Anonymous embed mode explicitly has no user claims to filter on. If you need a filtered public view, use an authenticated dashboard with an override that pins the filter to a fixed value.
What happens when the viewer's profile is missing an attribute?
The JWT claim is omitted. Your filter rule should set a defaultValue on the override, or the underlying data-source filter should treat the missing attribute as 'no rows' rather than 'all rows'. Fail closed.
Ready to embed?
Start on Professional with a 14-day free trial — no credit card, unlimited dashboards and users.