Documentsdify
Plugin Permissions
Plugin Permissions
Type
Topic
Status
Published
Created
Jul 7, 2026
Updated
Jul 7, 2026
Created by
Dosu Bot
Updated by
Dosu Bot

Plugin Permissions#

Dify controls plugin access through two overlapping systems: a legacy workspace-level permission model (predating RBAC) and a newer RBAC permission key system introduced in v1.15.0 . Understanding how they interact is essential when debugging unexpected access denials for editor/normal users.


Permission Systems#

Legacy Permission Model#

When RBAC is disabled, plugin access is governed by workspace-level settings stored in the Permissions object with two fields:

  • install_permission — controls who can install/update/delete plugins
  • debug_permission — controls who can use the plugin debugger

Each field accepts one of three values from PermissionType:

ValueMeaning
everyoneAll workspace members
adminsAdmins and owners only
nooneNo one

These settings are fetched from /workspaces/current/plugin/permission/fetch and updated via /workspaces/current/plugin/permission/change .

RBAC Permission Keys#

When RBAC is enabled, access is determined by whether workspacePermissionKeys (from useAppContext) contains specific string keys :

KeyControls
plugin.installInstall, update plugins
plugin.deleteDelete plugins
plugin.debugAccess the plugin debugger
plugin.plugin_preferencesEdit plugin preference settings

The hasPermission utility checks whether a given key exists in the user's workspacePermissionKeys array.


How They Interact: use-reference-setting.ts#

The central hook usePluginSettingsAccess computes all plugin capability flags by combining both systems.

canDebugPlugin — the conditional is RBAC-mode-aware :

if rbacEnabled → hasPermission(workspacePermissionKeys, 'plugin.debug')
else → hasLegacyPluginPermissionAccess({ permission: debug_permission, ... })

canInstallPlugin / canUpdatePlugin / canDeletePlugin — these use AND logic , requiring both an RBAC key and the legacy check to pass:

canInstallPlugin = hasPermission(workspacePermissionKeys, 'plugin.install') && legacyCanInstallPlugin

The legacy helper hasLegacyPluginPermissionAccess short-circuits to true when rbacEnabled !== false — so when RBAC is on, the legacy side of the AND always passes and only the RBAC key matters.


Known Bug: v1.15.0 (Fixed in PR #38197)#

In Dify 1.15.0, canDebugPlugin was incorrectly computed as :

canDebugPlugin = hasPermission(workspacePermissionKeys, 'plugin.debug') && legacyCanDebugPlugin

Because hasLegacyPluginPermissionAccess returns true when RBAC is on , the effective gate became only hasPermission(workspacePermissionKeys, 'plugin.debug'). Editor/normal users lacking the plugin.debug RBAC key were blocked from the debug modal even when the owner set debug_permission = everyone.

This was fixed by PR #38197 (merged June 30, 2026) to use a conditional rather than AND: when RBAC is enabled, only the RBAC key is checked; when disabled, only the legacy setting is checked.


Who Can Change Permission Settings#

The ability to modify workspace plugin permission settings is gated separately :

canSetPermissions = !rbacEnabled && hasPermission(workspacePermissionKeys, 'plugin.plugin_preferences')

When RBAC is active, the legacy permission UI is hidden entirely — permissions are managed through RBAC role configuration instead.


Key Files#

FilePurpose
plugin-permissions.tshasLegacyPluginPermissionAccess helper
use-reference-setting.tsComputes all can*Plugin flags; main entry point
types.ts (PermissionType)Enum for legacy permission values
utils/permission.tshasPermission RBAC key checker
service/use-plugins.tsAPI hooks for fetching/mutating permission settings
Plugin Permissions | Dosu