Package: slack-scim-rbac
Role Based Access Control for Slack-Bolt AppsRole Based Access Control (RBAC) is a term applied to limiting the
authorization for a specific operation based on the association of a User to a
"role".  For example:As an application developer, I want to ensure that only specific Users in a
given User-Group are allowed to execute the "bounce port" command.The Slack Platform does not natively support the concept of "User Groups", but
it does support the standard protcol: System for Cross-domain Identity
Management (SCIM).  A method for implemeting RBAC in Slack can be accomlished
using the Slack SCIM API feature.  For example:As an IT administrator of Okta, I will create SCIM groups that will designate
the specific RBAC User-Groups I want to use in Slack.Thisslack-scim-rbacrepository provides a Slack-Boltmiddlewareclass.As a developer using the SCIM protocol, you must obtain a SCIM Token from your Slack
administrator and export the environment variableSLACK_SCIM_TOKEN.The following code snippet is take from theexample.
In this example the User that entered the "bounce port" message must be a member
of the SCIM group "ChatOps-foo".  If they are not, then an error message is reported
to the User.fromslack_scim_rbac.middlewareimportAsyncSlackScimRBAC@app.message(re.compile("bounce port",re.I),middleware=[AsyncSlackScimRBAC(groups={"ChatOps-foo"})],)asyncdefapp_bounce_port(request:BoltRequest,context:BoltContext,say:Say):awaitsay(f"bouncing port for you <@{context.user_id}> ... standby")Customizing the Error ResponseAs a developer you will want to customize the error response to the User.
There are two ways to do this. The first way is to provide anerror_responsefunction to middleware addition.  For example this code will trigger a Modal
when the User triggers the/rbackercommand that contains the text "bounce
port" when they are not part of the "ChatOps-nofuzz" SCIM group.asyncdefis_bounce_port_command(command:dict):return"bounce port"incommand["text"]asyncdefmodal_no_you_cant(client:AsyncWebClient,body:dict,context:AsyncBoltContext):msg=f"Nope! Sorry <@{context.user_id}> but you cannot do that!"view=View(title="Permission Denied!",type="modal",close="Bummer")view.blocks=[SectionBlock(text=MarkdownTextObject(text=msg))]awaitclient.views_open(trigger_id=body["trigger_id"],view=view)@app.command(command="/rbacker",matchers=[is_bounce_port_command],middleware=[AsyncSlackScimRBAC(app_name=app.name,groups={"ChatOps-nofuzz"},error_response=modal_no_you_cant,)],)asyncdefslash_rbacker_bounce_port(ack:Ack,say:Say,context:Context):awaitack()awaitsay(f"Already then, <@{context.user_id}>, let's get to bouncing that port for ya!")The other approach is to sub-class theAsyncSlackScimRBACclass and
overriding theerror_responsemethod.Customizing the RBAC Validation ProcessBy default the validate process checks the Slack User groups (name) membership
in any of the required group names.  You can override this behavior (for
example if you have a default "admin" group that you want to always allow but
not require in each listener declaration) by sub-classingAsyncSlackScimRBACand overriding theis_membermethod.LimitationsThisslack-scim-rbacrepository implements middleware for asyncio mode only.
A sync implementation should be straightforward, but has not been done since it
is not what I needed.  If you do, please open an issue (or a PR).  Thanks!ResourcesSlack-Bolt for PythonVideo: Getting Started with Python Slack-Bolt PyCon 2021Article: What is SCIM?