How Superset permissions actually work
Superset inherits its security model from Flask-AppBuilder. Three concepts:
- A permission is an action, such as
can_read,can_write,can_export,menu_access,datasource_access,schema_access,database_access,all_datasource_access,all_database_access,can_sql_json. - A view menu is the thing the action applies to: a REST API (
Dashboard,Chart,Dataset), a menu entry (SQL Lab,Settings), or a data object named like[analytics].[finance].[gl_entries](id:42)for a dataset or[analytics].[finance]for a schema. - A permission view is the pair, and a role is a set of permission views. Users hold any number of roles, and their effective permissions are the union.
Two consequences shape the design. First, because permissions are unioned, roles can be small and composable; a user gets capabilities from one role and data from another. Second, there is no deny. If any role grants access to a dataset, the user has it. Design for that.
Dataset permissions are created automatically when a dataset is created and named after it, so the permission list grows with the catalogue. Schema permissions (schema_access on [db].[schema]) cover every current and future dataset in that schema, which is the lever that makes the model scale.
The default roles and where they stop
| Role | What it grants | Realistic use |
|---|---|---|
Admin |
Everything, including security settings | Two or three platform owners |
Alpha |
Access to all data sources, create and edit charts and dashboards, no security settings | Too broad for anyone in a multi-department deployment |
Gamma |
Read charts and dashboards for data sources granted separately; no SQL Lab | The right base for viewers and most builders |
sql_lab |
SQL Lab access, layered on another role | Analysts who write SQL |
Public |
Applied to unauthenticated visitors | Empty, unless you publish public dashboards deliberately |
Alpha is the problem. It carries all_datasource_access, so an Alpha user sees every dataset in every database connected to Superset. The moment two departments share an instance, Alpha is a policy violation waiting to be discovered. The design below uses it for nobody.
The model: capability roles plus data-domain roles
Split roles into two families and assign at least one from each.
Capability roles: what a person can do
| Role | Built from | Adds | Removes |
|---|---|---|---|
cap_viewer |
Gamma | Nothing | can_export on Chart and Dashboard if exports are restricted |
cap_explorer |
Gamma | can_explore on Superset, can_write on Chart (own charts), can_read on Dataset |
Dashboard editing |
cap_builder |
Gamma | Everything in explorer, plus can_write on Dashboard, can_read on CssTemplate |
|
cap_analyst |
Gamma + sql_lab | SQL Lab, can_sql_json, can_csv, saved queries |
Dashboard editing unless also a builder |
cap_curator |
cap_builder | can_write on Dataset, can_read on Database (to create virtual datasets and manage the catalogue) |
Database connection editing |
cap_admin |
Admin |
None of these grant any data. A user with only cap_builder can create a dashboard but has no datasets to put on it.
Data-domain roles: what a person can see
One role per data domain, granting schema_access on the schemas that belong to it, and nothing else:
| Role | Grants |
|---|---|
data_finance |
schema_access on [warehouse].[finance], schema_access on [warehouse].[finance_marts] |
data_sales |
schema_access on [warehouse].[sales] |
data_ops |
schema_access on [warehouse].[operations] |
data_hr_restricted |
datasource_access on specific HR datasets, not the schema, because the schema also contains payroll |
data_shared |
schema_access on [warehouse].[shared_dims], the calendar, geography and product dimensions everyone needs |
Prefer schema access. A new dataset created in the finance schema is visible to data_finance holders automatically, which is what the finance team expects. Use dataset-level access only when a schema contains a mix of sensitivities, and treat that as a signal to split the schema in the warehouse.
Putting them together
A finance analyst holds cap_analyst, data_finance, data_shared. A sales operations dashboard builder holds cap_builder, data_sales, data_ops, data_shared. A board member holds cap_viewer and data_finance. Adding a marketing department is one new data role and a mapping in the identity provider. Adding a new capability (say, alert creation) is one change to one capability role.
With five capability roles and ten domains you have fifteen roles, not fifty, and every one has a name a security reviewer can read.
Designing this for your actual org chart?
The capability/data-domain split above is the pattern; mapping it onto your specific teams, data domains, and SSO groups is the part that takes a workshop, not a blog post. A Superset Architecture Review does that mapping.
Dashboard permissions
Data-domain roles decide which datasets a user can query. They do not by themselves control which dashboards appear in the list. Two mechanisms do:
Default behaviour. A user sees a dashboard if they have datasource access to every dataset on it (or the dashboard is published and they have access to at least one chart’s data, depending on version). This falls out of the data roles and is usually enough.
Dashboard RBAC. With the DASHBOARD_RBAC feature flag on, a dashboard owner can attach roles to a dashboard under its properties. Users in those roles can view the dashboard even if they lack datasource access to its datasets, for that dashboard only. This is how you publish an executive summary built on restricted data to a wider audience without granting them the underlying tables.
FEATURE_FLAGS = {
"DASHBOARD_RBAC": True,
}
Use it deliberately. Because it bypasses dataset permissions, a dashboard with an over-broad role attached is a data exposure. Reserve the right to attach roles to curators, and review attachments quarterly (see the checks section).
Row-level security
RBAC decides which tables. Row-level security decides which rows. Under Settings, Row Level Security, a rule attaches a SQL clause to datasets for roles:
- Regular rules add a filter for the listed roles:
region = 'EMEA'on the sales datasets fordata_sales_emea. - Base rules apply to everyone except the listed roles, which is how you filter by default and exempt a headquarters role.
- Clauses can use Jinja:
owner_email = '{{ current_username() }}'for per-user filtering, withENABLE_TEMPLATE_PROCESSINGon.
RLS composes with the role design cleanly: data_sales grants the tables, data_sales_emea (a role with no permissions at all, used only as an RLS handle) restricts the rows. For customer-facing multi-tenant deployments the considerations are different and covered in multi-tenant RLS for embedded Superset.
SQL Lab and database-level controls
SQL Lab lets analysts run arbitrary SQL, subject to the schemas their roles grant. Controls that matter at scale:
- Per database connection, under Advanced, SQL Lab: expose in SQL Lab (off for databases nobody should query ad hoc), allow DML (off everywhere except a sandbox), allow file uploads (off).
SQL_MAX_ROWandDISPLAY_MAX_ROWin config, and per-database query timeouts, so one analyst cannot take down the warehouse.schema_accessis what limits which schemas appear in SQL Lab’s schema dropdown;database_accessalone exposes every schema, so grant schemas not databases.- Consider user impersonation on the connection for warehouses that support it (Snowflake, BigQuery, Postgres roles). Superset then runs the query as the logged-in user, and the warehouse’s own audit log attributes it.
Feeding roles from SSO
Hand-assigning fifteen roles to five hundred people is where good designs die. Every capability and data role should map from a group in the identity provider through AUTH_ROLES_MAPPING, with AUTH_ROLES_SYNC_AT_LOGIN = True so that a group change takes effect at the next login. The Okta guide shows the mechanics; the design here is what the mapping targets:
AUTH_ROLES_MAPPING = {
"bi-viewers": ["cap_viewer", "data_shared"],
"bi-builders": ["cap_builder", "data_shared"],
"bi-analysts": ["cap_analyst", "data_shared"],
"finance-all": ["data_finance"],
"sales-all": ["data_sales"],
"sales-emea": ["data_sales_emea"],
"bi-platform-admins": ["cap_admin"],
}
Group membership is now managed by the people who manage groups, with the identity provider’s approval workflow and audit trail, and Superset simply reflects it.
Roles as code
Clicking permissions into fifteen roles is error-prone and unrepeatable. Two ways to define them in configuration:
FAB_ROLES lets you declare roles as lists of regex pairs over view menu and permission names:
FAB_ROLES = {
"cap_viewer": [
[".*", "can_read"],
["Dashboard", "can_read"],
["Chart", "can_read"],
["Superset", "can_dashboard"],
["Superset", "can_slice"],
],
}
Roles declared here are created and kept in sync on superset init, and the config file becomes the policy document.
A provisioning script using the security manager’s API (add_role, find_permission_view_menu, add_permission_role) for the data-domain roles, run as part of deployment, reading the schema list from a YAML file. This is what we do for larger deployments because schema permissions are data-driven and a regex over [warehouse].[finance.*] is fragile.
Either way, keep the definition in version control and treat a role change like a code change: reviewed, tested in staging, deployed.
The checks that keep it honest
A role model drifts. These queries against the metadata database, run monthly, catch the usual drift:
- Nobody holds Alpha.
SELECT u.username FROM ab_user u JOIN ab_user_role ur ON u.id = ur.user_id JOIN ab_role r ON r.id = ur.role_id WHERE r.name = 'Alpha'. Expected: empty. - Admin count is small and known. Same query for
Admin. Expected: the platform owners, nobody else. - No role grants `all_datasource_access` except Admin. Check
ab_permission_view_rolejoined to permissions. - Every dataset’s schema is covered by exactly one data role, so that a new dataset is not accidentally visible through two domains.
- Dashboard RBAC attachments list, with owners, for review.
- Users with no data role (they can log in and see nothing), which usually means an SSO group mapping is missing.
- Users not seen for 90 days, for deactivation.
Put the results in a dashboard. Superset is quite good at those.
Where to start if you have the everyone-is-Alpha deployment
- Inventory users, roles and dataset permissions from the metadata database.
- Define the data domains from the warehouse schemas, and the capability roles from what people actually do (most are viewers).
- Create the new roles alongside the old ones, map SSO groups, and give a pilot department the new roles in addition to their old ones.
- Verify the pilot sees what they should and nothing more, then remove their old roles.
- Repeat per department. Remove Alpha last, once the last department is migrated.
Expect two to four weeks for a five-hundred-user deployment, most of it in conversations about who should see what, which is the conversation the deployment should have had at the start.
Frequently Asked Questions
Why is giving everyone the Alpha role a problem?
Alpha grants access to every dataset in the deployment, including ones added after the role was assigned, plus the ability to edit them. At fifty users that is untidy. At five hundred it means no one can answer the question an auditor actually asks, which is who can see a given table and why. The role model below exists so that question has an answer that does not depend on memory.
How many roles does a 500-user Superset deployment need?
Fewer than most teams expect, if the roles compose. Splitting them into capability roles (what a person can do) and data-domain roles (what a person can see) means a new department is one new data role rather than a full set of duplicates. A deployment of this size typically lands between twelve and twenty roles in total, not one per team.
Does row-level security replace role-based access control?
No, it narrows it. RBAC decides whether someone reaches a dataset at all; RLS decides which rows they see once they are there. They are designed to work together: a data-domain role grants the tables, and an RLS rule attached to a permission-free handle role restricts the rows. Using RLS alone to do both leaves the dataset itself reachable.
Can Superset roles be assigned automatically from Okta or Entra ID?
Yes, and they should be at this scale. Map every capability and data role to a group in the identity provider through AUTH_ROLES_MAPPING, and set AUTH_ROLES_SYNC_AT_LOGIN = True so a group change takes effect at the user’s next login. Access is then granted and revoked where the rest of your joiners-and-leavers process already lives.
Build It With Andolasoft
Role design is the second thing we look at in a Superset Architecture Review, after authentication: who has Alpha, how datasets are granted, whether RLS is doing what people think it is, and what the drift checks find. It is a fixed-scope, five-day review with a written report. If you would rather the role model were maintained for you, alongside patching and monitoring, that is Managed Support.
If you are looking at an everyone-is-Alpha deployment and an audit date, talk to us. We will map your current roles and dataset grants, show you where the real exposure is, and give you a fixed-scope plan to the model described above.