Permission Registration#
Superset uses Flask-AppBuilder (FAB) as its underlying permission framework, extended by SupersetSecurityManager in superset/security/manager.py. Permissions are modeled as PermissionView (PVM) records — a composite of a Permission (action name, e.g. can_read) and a ViewMenu (resource name, e.g. Dashboard). All creation and deduplication flows ultimately call FAB's add_permission_view_menu().
Initialization Trigger: superset init#
Permissions are not automatically registered on every app startup. They must be explicitly provisioned via the CLI command :
superset init
This command does two things in sequence:
appbuilder.add_permissions(update_perms=True)— Walks all registered FAB views and ensures every auto-generated CRUD permission (e.g.can_read,can_write) has a corresponding PVM row in the database.security_manager.sync_role_definitions()— Registers Superset's custom permissions, assigns them to the default roles (Admin, Alpha, Gamma, sql_lab), fills in any missing datasource/database PVMs, and deletes orphaned PVMs.
sync_role_definitions Flow#
Defined at , this method orchestrates the full permission sync:
| Step | Method | Purpose |
|---|---|---|
| 1 | create_custom_permissions() | Registers Superset-specific PVMs (e.g. all_datasource_access, can_sqllab, can_tag) |
| 2 | set_role() | Rebuilds default role membership from all PVMs using predicate functions |
| 3 | create_missing_perms() | Adds PVMs for any database/dataset/schema objects not yet covered |
| 4 | clean_perms() | Deletes PVMs where either the Permission or ViewMenu side is NULL |
The PUBLIC_ROLE_LIKE config key optionally mirrors an existing role's permissions onto the public role.
Deduplication Mechanism#
FAB's add_permission_view_menu() (inherited, not overridden in Superset) handles its own deduplication internally — it does not insert a duplicate PVM if the (Permission, ViewMenu) pair already exists.
Superset adds a second layer inside create_missing_perms: it snapshots all existing PVMs into a Python set at the start of the call, then guards every add_permission_view_menu call with an explicit membership check via the local merge_pv helper. This avoids redundant DB round-trips.
The deprecated merge_perm() wrapper is an alias for add_permission_view_menu() and should not be used in new code.
Feature-Flag-Gated Permissions: TAGGING_SYSTEM#
The TAGGING_SYSTEM feature flag (defaults to False) gates the tagging subsystem in two distinct ways:
1. Event Listeners (runtime, init_app_in_ctx):
During app startup, SupersetAppInitializer.init_app_in_ctx() checks the flag and conditionally calls register_sqla_event_listeners(), which hooks SQLAlchemy after_insert/after_update/after_delete events on SqlaTable, Slice, Dashboard, FavStar, and SavedQuery models to keep tag associations in sync.
2. Tag Permissions (always registered):
The can_tag permissions on Chart and Dashboard are registered unconditionally inside create_custom_permissions() — they exist in the database regardless of the feature flag. The flag only controls:
- Whether SQLAlchemy event listeners fire
- Whether the Tags menu appears in navigation (via
menu_condininit_views()) - Whether
TagModelView/TagViewreturn404when the flag is off
This means disabling TAGGING_SYSTEM does not remove can_tag PVMs. Any role that had can_tag granted will still hold it; the endpoints just become unreachable.
Role Assignment Logic#
set_role() rebuilds each role's PVM list on every superset init using predicate functions:
- Admin: All non-user-defined PVMs
- Alpha: Excludes admin-only, SQL Lab-only, and user-defined PVMs
- Gamma: Excludes admin-only, alpha-only, SQL Lab-only, and user-defined PVMs
- sql_lab: PVMs in
SQLLAB_ONLY_PERMISSIONSandSQLLAB_EXTRA_PERMISSION_VIEWS
User-defined permissions (OBJECT_SPEC_PERMISSIONS: database_access, catalog_access, schema_access, datasource_access) are never assigned to any built-in role — they are managed per-object via SQLAlchemy event hooks .
Key Source Files#
| File | Purpose |
|---|---|
superset/security/manager.py | SupersetSecurityManager — all permission CRUD, role sync, deduplication |
superset/initialization/__init__.py | SupersetAppInitializer — app startup, TAGGING_SYSTEM flag check |
superset/cli/main.py | superset init CLI entry point |
superset/tags/core.py | SQLAlchemy event listener registration / removal for tagging |