Progressive permissions for Slack apps

Leo Sjöberg • March 19, 2023

With Slack's deprecation of its legacy Workspace Apps, the ability to interactively request further permissions was lost. However, you can still request an extend permission scope using your own implementation. For my Slack App, Decisionlog, I needed to request the channels:history scope, which allows me to read the messages in a channel or thread. However, I only need this scope when the user is trying to record a decision from a message or for a thread (so that I can include the message in the decision, and in the future help summarise the thread for them).

The key to this is to use the scope parameter that is specified in the Slack OAuth URL. In order to request additional scopes, simply add what you need to the scope parameter. One important caveat here is that it means you should not specify your optional scopes in the Slack API configuration panel, as that changes the default scopes that are requested by the "Add to Slack" button. As far as I can tell, however, the scope configuration in the configuration panel are only used to generate the "Add to Slack" button, not impacting your application's ability to request additional scopes.

Putting it into practice, my "Embeddable Slack button" looks like this:

1<a href=",chat:write,chat:write.public&user_scope="><img alt="Add to Slack" height="40" width="139" src="" srcSet=" 1x,[email protected] 2x" /></a>

As such, when I want to request the channels:history scope, I simply add it to the scope parameter:

-scope=commands,chat:write,chat:write.public //
+scope=commands,chat:write,chat:write.public,channels:history //

Then, I implement a custom button in my Slack App's homepage to let the user grant the additional scope to the App.

When building applications, it's important to only request the permissions you need. This is especially true for ones like Slack Apps, where permission may be granted to your service to read all messages, which could very well contain sensitive information. In the case of Decisionlog, I only need to read the messages in a channel or thread when the user wants to include the message in the decision, meaning I can build both trust and a more secure application by not requesting extraneous permissions ahead of time.